#include <SPI.h>
#define ADDRESS_SLAVE 0x21
#define ATT_CLK 3
#define ATT_DAT 4
#define ATT_LE 5


void configureAttenuator() {
  digitalWrite(ATT_LE, LOW);
  byte data[6] = { 0, 0, 0, 0, 0, 0 };  // ATT LEVEL 
  digitalWrite(ATT_CLK, LOW);
  digitalWrite(ATT_LE, LOW);
  for (int i = 0; i < 6; i++) {
    digitalWrite(ATT_DAT, data[i] ? HIGH : LOW);
    delayMicroseconds(1);  // Serial data set-up time before clock rising edge - min 10ns
    digitalWrite(ATT_CLK, HIGH);
    delayMicroseconds(1);  // Serial clock HIGH time - min 30ns
    digitalWrite(ATT_CLK, LOW);
    delayMicroseconds(1);  // Serial clock LOW time - min 30ns
  }
  delayMicroseconds(1);  // LE set-up time after last clock falling edge - min 10ns
  digitalWrite(ATT_DAT, LOW);
  digitalWrite(ATT_LE, HIGH);
  delayMicroseconds(1);  // LE minimum pulse width - min 30ns
}

void configurePLL()  // 100MHz
{
  uint32_t regs[6] = {
    /*R0*/ 0x400000,
    /*R1*/ 0x8008011,
    /*R2*/ 0x1008F42,
    /*R3*/ 0x4B3,
    /*R4*/ 0xDC803C,
    /*R5*/ 0x580005
  };

  // void configurePLL() // 200MHz
  // {
  //     uint32_t regs[6] = {
  //     /*R0*/ 0x400000,
  //     /*R1*/ 0x8008011,
  //     /*R2*/ 0x1008F42,
  //     /*R3*/ 0x4B3,
  //     /*R4*/ 0xCC803C,
  //     /*R5*/ 0x580005
  //   };

  // void configurePLL() // 400MHz
  // {
  //     uint32_t regs[6] = {
  //     /*R0*/ 0x400000,
  //     /*R1*/ 0x8008011,
  //     /*R2*/ 0x1008F42,
  //     /*R3*/ 0x4B3,
  //     /*R4*/ 0xBC803C,
  //     /*R5*/ 0x580005
  //   };

  // void configurePLL() // 800MHz
  // {
  //     uint32_t regs[6] = {
  //     /*R0*/ 0x400000,
  //     /*R1*/ 0x8008011,
  //     /*R2*/ 0x1008F42,
  //     /*R3*/ 0x4B3,
  //     /*R4*/ 0xAC803C,
  //     /*R5*/ 0x580005
  //   };

  pinMode(13, OUTPUT);
  pinMode(14, OUTPUT);
  digitalWrite(14, HIGH);
  for (int i = 0; i < 6; i++) {
    uint32_t reg = regs[5 - i];
    digitalWrite(13, LOW);
    delayMicroseconds(10);
    SPI1.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
    for (int j = 0; j < 4; j++) {
      SPI1.transfer(reg >> ((3 - j) * 8) & 0xFF);
    }
    SPI1.endTransaction();
    delayMicroseconds(10);
    digitalWrite(13, HIGH);
    delayMicroseconds(10);
  }
}

void setup() {
  SPI1.setRX(12);   // MISO
  SPI1.setTX(11);   // MOSI
  SPI1.setSCK(10);  // SCK
  SPI1.begin(false);

  Serial.begin(9600);
  while (!Serial);
  Serial.println("Test of PLL and ATT");

  pinMode(ATT_CLK, OUTPUT);
  pinMode(ATT_DAT, OUTPUT);
  pinMode(ATT_LE, OUTPUT);
  digitalWrite(ATT_LE, HIGH);

  configurePLL();
  configureAttenuator();
}

void loop() {
  delay(3000);
}