Using SPI to interact with the AD9958 synthesizer - WCP52/docs GitHub Wiki
Some basics
- Max sclk frequency allowed is 200 MHz
- CPOL = 0
- the base value of the clock is 0
- CPHA = 1
- data is propagated on the rising edge of sclk
- data is read on the falling edge of sclk
- CS idles high and is driven low to begin communication
- drive CS low
- drive sclk high
- data is on the line when sclk rises and read when sclk falls
AD9958's communication protocol
- First send an 8 bit instruction
- Bit 7 determines read/write
- 1 for read
- 0 for write
- Bits [4:0] determine which address to write to
- Bit 7 determines read/write
- sclk is driven low after the last instruction byte is sent until data is ready to be sent. On the rising edge after the last instruction byte, AD9958 begins reading data.
- The next transfer is the information we are sending to the register
- In AD9958's protocol, we must send a number of bits equal to the size of the register. So, if the datasheet specifies that the register is 32 bytes, we should send all 32 bytes in this communication.
- If we fail to send all the bytes that AD9958 is expecting, it will wait for them. On our next transmission, we may believe that we are sending an instruction byte, but in fact, AD9958 is reading data to the same register as before.
- Once AD9958 receives all of the necessary bytes, it expects the next transfer to be an instruction byte.
- In order to move data from the i/o buffer to the synthesizer's internal registers, we must send an IO update. This is done by setting the IO Update pin on the synthesizer high for 4 period of the chip's sysclk.
What we need to do
This project is going to use two DDRs. One is to send a sweep of frequencies to the DUT, but, since we need to sample at each frequency, the microcontroller will do the sweep. The other is used as a reference for phase. In order to do this, we activate only one channel at a time and send the necessary data.
First we need to do some initial configuration to the synthesizer chip.
-
Set the chip to LSB first mode.
- Send instruction byte to write to addr 0x00: cmd = 0x80
- Turn on LSB mode: cmd = 0x01
- Send IO Update
-
Configure function register 1:
- Bit 23: VCO gain control: b1 for 500 MHz clock
- Bits 22:18: PLL divide ratio: 20 for 500 MHz clock
- Bits 17:16: PLL charge pump control: b00 for default 75uA
- Bits 14:12: Profile pin configuration: b000 (not used)
- Bits 11:10: Ramp-up/ramp-down: b00: disabled
- Bits 9:8: Modulation level: b00 (not used)
- Bit 7: Reference clock input power-down: b0: enable
- Bit 6: External power-down mode: b0: fast recovery mode/default
- Bit 5: SYNC_CLK: b0: enabled
- Bit 4: DAC reference power-down: b0: DAC ref enabled
- Bit 1: Manual hardware sync: b0: disabled
- Bit 0: Manual software sync: b0: disabled
-
Send IO update
-
Configure function register 2:
- Bit 15: All channels autoclear sweep accumulator: b0: no
- Bit 14: All channels clear sweep accumulator: b0: no
- Bit 13: All channels autoclear phase accumulator: b0: no
- Bit 12: All channels clear phase accumulator: b0: no
- Bit 7: Auto sync enable: b0
- Bit 6: Multidevice sync master enable: b0
- Bit 5: Multidevice sync status: b0
- bit 4: Multidevice sync mask: b0
- Bits 1:0: System clock offset: b0
-
Send IO update
Now we can set a frequency tuning word. For this example, I will use channel 0. For channel 1, just change the CSR write (addr 0x00) from 0x41 to 0x81
- Enable editing of channel 0 only
- Send instruction byte to write addr 0x00: cmd = 0x80
- Enable channel 0 only: cmd = 0x41
- Set Frequency Tuning word in CFTW0 (addr 0x04)
- Send instruction byte to write addr 0x04: cmd = 0x84
- Set frequency tuning word where
- fout = ((FTW)(fs))/(2^32)
- fs = 500 Mhz
- suppose we want a frequency of 100 Mhz, then we send 0x33333333
- fout = ((FTW)(fs))/(2^32)
- Send IO Update