ADF4153 12Ghz PLL Umbau und Programmierung.

Auf der HAM-Radio 2018 in Friedrichshafen hat Alex (DL8AAU) schöne PLL-Bausteine entdeckt, welche sich für den Frequenzbereich von ca. 11-13,5 GHz eignen.

Ich werde die PLL verwenden um mittels eines Verdreifachers ein 38 GHz Signal zu erzeugen. Dies wird als LO für einen 76 GHz Subharmonischen-Mischer nach DB6NT benötigt.

12 GHz PLL-Baustein geöffnet.

Die Bausteine enthalten einen Transistor-VCO (Sollfrequenz/4) den man mittels Lötzinn und Fähnchen schön auf Sollfrequenz abgleichen kann. Der VCO wird über ein ADF4153 PLL-IC an einen internen 20 MHz Quarzoszillator angebunden. Danach wird das Signal durch einen HMC189 passiv verdoppelt und durch einen Bandpass gefiltert. Jetzt wird das Signal nochmals mit einem HMC369 aktiv verdoppelt und wieder durch einen Bandpass gefiltert. Zum Schluss folgt noch eine Verstärkerstufe mit HMC441, welcher dann ca. +15 dBm am Ausgang abliefert.

Der Abgleich des VCO per Lötkolben war sehr einfach und Problemlos. Zielfrequenz war in diesem Fall erst mal die (24.048 GHz – 146 MHz) / 2 also 11,951 GHz. Diese LO-Baugruppe wird im 24 GHz Transverter für DR9A ihre Verwendung finden.

Spektrum bei 11,5 GHz freilaufender VCO.

Nun muss der PLL-Chip noch seine Programmierung bekommen. Hierzu verwende ich einen Arduino Pro Mini, Der ADF4153 wird per SPI programmiert. Hierzu werden die benötigten Register über ein paar digital Pins des Arduino per “Bit Banging” in den ADF4153 geladen.

Leider habe ich keinen passenden Stecker gefunden und musste diesen erst beschaffen. Dank an Alex (DL8AAU) für die Identifizierung und Bestellung.

Belegung des Steckers:

Pin 1: Clock
Pin 2: Data
Pin 3: LE
Pin 4:
Pin 5: Ground
Pin 6: 10V DC

Der Logikpegel zum programmieren ist 3,3V, es muss also ein passender Mikrocontroller verwendung finden oder die Pegel müssen geeignet angepasst werden.

Der Arduino Pro Mini wird wie folgt angeschlossen:

Clock an Pin 13
Data an Pin 11
LE an Pin 03

Arduino Pro Mini.

Nach erfolgter Programmierung des PLL-Chip rastete der Oszillator sofort ein. Selbst mit dem internen 20 MHz TCXO ist die Frequenz schon auf wenige Hertz genau getroffen. Als nächstes erfolgt der Umbau auf 10 MHz Referenz, welche dann extern über Pin 4  zugeführt wird.

Der Umbau auf 10MHz Referenz ist recht einfach, das schwierigste ist es den internen 20 MHz Oszillator zu entfernen. Da ich nicht vor hatte den Oszillator wieder zu verwenden, habe ich ihn komplett mit dem Lötkolben erhitzt, wodurch sich die Abschirmhaube abnehmen ließ. Danach waren alle Anschlüsse gut zugänglich und konnten mit Entlötlitze “leergesaugt” werden. Danach mit einem Skalpell unter die Platine hebeln und gleichzeitig nach und nach die Lötstellen ablösen. Danach wird die Leiterbahn, welche zu Pin 4 der Steckerleiste führt, mittels Skalpell getrennt. Nun wird ein Stück Fädeldraht vom ehemaligen Ausgangs-Pin des 20 MHz Oszillators zu Pin 4 gelegt. Fertig ist der Umbau.

Verschiedene Quellen sagen, dass man der VCO-Stromversorgung noch etwas mehr Kapazität verpassen sollte. Ich werde dies mal ausprobieren und einen Vorher/Nachher Messung anfertigen.

Mittlerweile ist der Oktoberkontest 2018 rum und leider hat die PLL Ärger gemacht. Sie hat extrem viel Rauschen produziert, so dass an einen Betrieb mit dem Transverter auf 24 GHz nicht zu denken war.

Nun geht es an die Ursachenforschung und an die Beseitigung der Probleme. … nach dem Kontest ist vor dem Kontest …

Nachfolgend der Source-Code mit dem der PLL-Chip programmiert wird. Es handelt sich um eine Abwandlung der Source von Wolfgang (OE8WOZ). Vielen Dank für die Erlaubnis den Code zu verwenden !

Oszillator bei 11.951 GHz gerastet.

// uncomment either line: upper means no debug, lower adds serial debug (max. 80ch/line)
//#define DEBUG(...) {}
#define DEBUG(...) {char s[80]; sprintf(s,__VA_ARGS__); Serial.println(s);}

// we use the LCD shield, the AVR EEPROM and SPI interface
#include <SPI.h>

// some may vary, depending on setup (only SPI pins are hardcoded)
#define ADF4153_LE 3    // ADF select

// reference used on PLL board, you may need to adapt this
//                     MMkkkHHH
const uint32_t REFin = 10000000; // Hz 
// set to "real" reference freq. - e.g. in my case it is: 24999518

// PLL parameters kept global, may be used by several functions
uint32_t fpfd; // internal phase comparison frequency
uint8_t I_BLEED_N,RFA,RFB,PWR; // used in loop, but kept constant for now
uint8_t D, T, R, CP; // only used in INIT for now
uint32_t PLL_R10, PLL_R04_RES, PLL_R04; // calculate once, then reuse

// global variables for GUI handling
//                GGMMMkkk...LL in Hz
uint64_t RFout =  1195100000LL;  // output frequency
uint64_t steps =     1000000LL;  // actual value for increment/decrement of freq.
int setpos=7;                    // position on screen, must match with steps above

// write an ADF register
void writeRegADF(const uint32_t value)
{
  // 32bit transfer
  SPI.transfer((value >> 24) & 0xFF);
  SPI.transfer((value >> 16) & 0xFF);
  SPI.transfer((value >> 8) & 0xFF);
  SPI.transfer((value >> 0) & 0xFF);
  digitalWrite(ADF4153_LE, HIGH);
  digitalWrite(ADF4153_LE, LOW);

  // show what we have written
  DEBUG("%08lx",value);
}
// Program all the registers of the ADF4153 the first time
void initADF()
{ uint16_t VCO_BDIV; // 8bit
  uint16_t ADCDIV;   // 8bit
  uint16_t Timeout;  // 8bit
  uint8_t ALC_TO, LOCK_TO; // each 5bit

  DEBUG("REF: %ld.%06ld MHz",(long)(REFin/1000000L),(long)(REFin%1000000L));

  // some initial global settings
  I_BLEED_N=9; CP = 2;
  PWR=0;
  RFA=0;
  RFB=0;
  // this ensures fref = 2*fpfd for best noise performance (OK if fref <62.5MHz) 
D = 1; T = 0; R = 1; // PFD is derived from above settings fpfd = REFin*(1+D)/(R*(1+T)); DEBUG("PFD: %ld.%06ld MHz",(long)(fpfd/1000000L),(long)(fpfd%1000000L)); // calculate registers for ADC (and round-up) ADCDIV = (fpfd/100000L)>>2;
  if (ADCDIV>255) ADCDIV=255;

  // VCO band division (and round-up)
  VCO_BDIV = ((fpfd/1200000L)+1)>>1;
  if (VCO_BDIV>255) VCO_BDIV=255;

  // calculate registers for timeout (and round-up)
  Timeout = ((fpfd/500000L)*50/30+1)>>1;
  if (Timeout>255) Timeout=255;
  ALC_TO=30;
  LOCK_TO=12;

  // show in readable format
  DEBUG("ADCDIV  = %d",ADCDIV);
  DEBUG("VCO_BDIV= %d",VCO_BDIV);
  DEBUG("Timeout = %d",Timeout);
  DEBUG("ALC_TO  = %d",ALC_TO);
  DEBUG("LOCK_TO = %d",LOCK_TO);

  // we re-use them later in the frequency set function as well, so define it once here
  PLL_R10 = (0x00c0003aL)|((uint32_t)ADCDIV<<6);
  PLL_R04     = (0x4L)|(6L<<27)|((uint32_t)D<<26)|((uint32_t)T<<25)|((uint32_t)R<<15)|(1L<<14)|((uint32_t)CP<<10)|(1L<<9)|(1L<<8)|(1L<<7);
  PLL_R04_RES = PLL_R04|(1L<<4);

  // update registers
  writeRegADF(0x1041cL);   // R12: normal operation, no phase sync
  writeRegADF(0x61300bL);  // R11: reserved
  writeRegADF(PLL_R10); // R10: ADCEN=1, ADCCONV=1, clock divider
  writeRegADF((0x9L)|((uint32_t)VCO_BDIV<<24)|((uint32_t)Timeout<<14)|((uint32_t)ALC_TO<<9)|((uint32_t)LOCK_TO<<4)); // R9: timeout settings
  writeRegADF(0x102d0428L);  // R8: reserved
  writeRegADF((0x10000007L)|(1L<<25)|(3L<<8)|(3L<<5)); // R7: PLL settings for fractional mode and lock behaviour
  writeRegADF((0x35000006L)|((uint32_t)RFB<<10)|((uint32_t)RFA<<6)|((uint32_t)PWR<<4)); // R6: output settings (initial)
  writeRegADF(0x800025L);  // R5: reserved
  writeRegADF(PLL_R04_RES); // R4: PLL setup, incl. f_pfd settings, PLL kept in reset
  writeRegADF(0x00000003L); // R3: phase adjust / resync not used
  writeRegADF((0x2L)|(2L<<4)); // R2: lowest possible setting, we override this later with the actual frequency
  writeRegADF((0x1L)|(1L<<4)); // R1: lowest possible setting, we override this later with the actual frequency
  delay(3);
  writeRegADF((0x0L)|(75L<<4)); // R0: lowest possible setting, we override this later with the actual frequency } // Set a new frequency on the ADF4153 void updateADF(uint64_t freq) { uint16_t INTR, FRAC2R, MOD2R; // 16bit, 14bit, 14bit uint32_t FRAC1R; // 24bit uint8_t RF_Select; // 6 bit DEBUG("OUT: %ld.%06ld MHz",(long)(freq/1000000L),(long)(freq%1000000L)); // set up VCO frequency window RF_Select=0; if (freq>6800000000LL) {
    freq>>=1;
    RFA=0;
    RFB=1;
  } else {
    while (freq<3400000000LL) {
      freq<<=1;
      RF_Select+=1;
    }
    RFA=1;
    RFB=0;
  }

  DEBUG("VCO: %ld.%06ld MHz, MAIN:%s, AUX:%s",(long)(freq/1000000L),(long)(freq%1000000L),RFA?"on":"off",RFB?"on":"off");

  // calculate registers for fout
  INTR = freq/fpfd;
  uint32_t remainder = ((freq-INTR*fpfd)<<32)/fpfd; FRAC1R = remainder>>8;
  MOD2R = 256;
  FRAC2R = remainder&255;

  DEBUG("RFDIV = %d",1<<RF_Select);
  DEBUG("INT   = %d",INTR);
  DEBUG("FRAC1 = %ld",FRAC1R);
  DEBUG("FRAC2 = %d",FRAC2R);
  DEBUG("MOD2  = %d",MOD2R);

  // update registers, acc. to specification
  writeRegADF(PLL_R10);                                             //R10
  writeRegADF((0x35000006L)|((uint32_t)RF_Select<<21)|((uint32_t)I_BLEED_N<<13)|((uint32_t)RFB<<10)|
              ((uint32_t)RFA<<6)|((uint32_t)PWR<<4));               //R6
  writeRegADF(4L|((uint32_t)PLL_R04_RES));                          //R4  DB4=1
  writeRegADF(2L|((uint32_t)MOD2R<<4)|((uint32_t)FRAC2R<<18));      //R2
  writeRegADF(1L|((uint32_t)FRAC1R<<4));                            //R1
  writeRegADF(0L|(uint32_t)INTR<<4);                                //R0  PRE is always 4/5
  writeRegADF(PLL_R04);                                             //R4  DB4=0
  delay(3); //  VCO stabilization
  writeRegADF(0L|0x200000L|((uint32_t)INTR<<4));                    //R0  enable autocal
}

//=====================================================================
// ARDUINO SETUP CALL (mandatory, do HW setup, do ADF4153 setup)
//=====================================================================

void setup() {
  // Init PLL I/O
  pinMode(ADF4153_MUX, INPUT);
  pinMode(ADF4153_LE, OUTPUT);
  digitalWrite(ADF4153_LE, HIGH);

  // Init PLL SPI bus
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);

  // Init serial (for debug)
  Serial.begin(115200); 
  
  // start-up message
  Serial.println();
  Serial.println("ADF4153 master, (c) 2018 OE8WOZ");

  // Init PLL
  digitalWrite(ADF4153_LE, LOW);
  initADF();
  delay(10);
  updateADF(RFout);
  delay(10);
}

//=====================================================================
// ARDUINO LOOP CALL (mandatory, reads keys and update ADF4153)
//=====================================================================

void loop() {  
  }
Getagged mit: , , , ,

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*