/*

2023-05-02, S53DZ
A=0, B=16, P=8 => N=128 (1/256)
A=0, B= 8, P=8 => N= 64 (1/128)

BG7TBL 6 GHz Prescaler Division Ratios by Bryce Cherry
Microcontroller is an ATtiny25 and runs on its internal calibrated 8 MHz RC oscillator with PCB provision for an external crystal + load capacitors.
For adding support for ATtiny25 (and certain others), visit https://github.com/MCUdude/MiniCore

U5 is a divide-by-2 flip-flop (most likely a TC74WH74) which is connected after the ADF4106 MUX output for regulating output duty cycle to 50%.
At a 1000000 division ratio, positive pulses at the ADF4106 MUX output are measured at ~6.4uS wide at 10 MHz, ~120nS at 500 MHz and ~60nS at 1 GHz.

ICSP header (JP2 - Pin 1 has a square pad - +3.3V LEVELS ONLY OR DAMAGE WILL OCCUR!) - we won't need a bootloader here:
  
  5 MOSI (PB0)
  6 MISO (PB1)
  7 SCK (PB2)
  1 /RESET (PB5 - has 10K pullup to +3.3V)
  GND 4  
+3.3V 8  

+3.3V current draw on this board is approximately 30 mA.
Although the original BG7TBL program and EEPROM data has been read protected, ISP programming (without requiring switching of +12V on Reset pin) is still possible.
The common of the prescaler ratio switches is connected to GND and internal pullup resistors are used in this microcontroller for this code.

*/

#define ADF4106_CLK PB0 //  pin 5
#define ADF4106_DATA PB4 //  pin 3
#define ADF4106_LE PB3 //  pin 2
#define StatusLED PB2 //  pin 7
// A0 (TQFP pin 3) is used for an analog function (sample and hold filter on the output for monitoring duty cycle) which will not be used here

 int PrescalerSW[2]={3,5};// TQFP pins 1 (Switch /Bit 0) and 9 (Switch /Bit 1) respectively - pins which can be easy to solder to have been chosen here
// Origianl BG7TBL program logic analysis:
// Four bytes are sent for every LE cycle (first byte is dropped by the ADF4106 on loading the fourth byte) and CLK is idle high - my code only sends the required three bytes for each cycle.
// Sequence: Reference, N Counter, Function - the Initialization latch is not programmed although the same data cycle (not required) is repeated a short time later.
uint32_t registers[3] = {0x00C00022, 0x001E8481, 0x00000FA0}; // Prescaler=64 and MUX=N, A=32 B=7812 (division ration 500000), Reference=1000
byte oldposition; // old frequency for comparison against switch changes
byte position; // switch position
unsigned int i = 0;

void setup() {
  pinMode(ADF4106_CLK, OUTPUT);
  pinMode(ADF4106_DATA, OUTPUT);
  pinMode(ADF4106_LE, OUTPUT);
  pinMode(StatusLED, OUTPUT);
  for(int i=0; i<2; i++){
  //pinMode(PrescalerSW[i], INPUT_PULLUP);
  }
  digitalWrite(ADF4106_LE, HIGH);
  digitalWrite(StatusLED, LOW);
  //digitalWrite(StatusLED, HIGH); //ON
  oldposition=0x0E; // in a position a 0-3 switch cannot do
  delay(2500); // ensures that the ADF4106 is stable after power on
}

void loop() {
    byte position=0x00; // Clear the position byte for a new read
    position = 0x02; // varianta N=128, A=0, B=4, P=32
  switch(position) {
    // Division ratio calculation: ((Prescaler * B) + A) where A is 0-63, B is 3-8191 and Prescaler is 8/16/32/64
    // With Prescaler 8, A=0 and B=3, minimum division ratio is 24.
    case 0x00: // 1/128 (256 with external flip-flop)
      registers[1]=0x00001001; // A=0, B=16
      registers[0]=0x00000022; // Prescaler=8 and MUX=N
      break;
    case 0x01: // 1/128 (256 with external flip-flop) 
      registers[1]=0x00000801; // A=0, B=8
      registers[0]=0x00400022; // Prescaler=16 and MUX=N
      break;
    case 0x02: // 1/128 (256 with external flip-flop) 
      registers[1]=0x00000401; // A=0, B=4
      registers[0]=0x00800022; // Prescaler=32 and MUX=N
      break;
  }
    if (oldposition != position){
		digitalWrite(StatusLED, LOW); //OFF
		//digitalWrite(StatusLED, HIGH); //ON
		SetADF4106();
		oldposition=position; // Update old frequency
		delay(500);
		digitalWrite(StatusLED, HIGH); //ON
		//digitalWrite(StatusLED, LOW); //OFF
    }
    delay(25000);
}

void SetADF4106(){
    for (int i = 2; i >= 0; i--){
    WriteRegisterADF4106(registers[i]);
    }
}

void WriteRegisterADF4106(const uint32_t value) {
  digitalWrite(ADF4106_CLK, LOW); // correct clock phase
  digitalWrite(ADF4106_LE, LOW);
  for (int i = 2; i >= 0; i--){
  shiftOut(ADF4106_DATA, ADF4106_CLK, MSBFIRST, ((value >> 8 * i) & 0xFF));
   }
  digitalWrite(ADF4106_LE, HIGH);
 }
