Part Number: DAC38J84
Dear TI Supporters,
The DAC38J84 SerDes PLL is not locking in our system. Will you help diagnose the problem?
We are integrating Abaco FMC144 with an Intel Arria 10 SoC Dev Kit.
There is no reference design; we have developed our code by referring to the DAC3XJ8X GUI v1.2 (in simulation mode) and the BSP made available by Abaco.
Our application operates the four converters independently.
The DAC38J84 DACCLK input is driven correctly, because the FPGA measures other DCLKoutX outputs at the desired frequency, and all DCLKoutX outputs are programmed at the same frequency.
The FPGA receives the expected SYSREF pulse train, as captured in signaltap.
Here are the key parameters:
LMFS: 4421
Sample rate: 148.5Msps
Ext CLK; bypass (disable/reset) DAC PLL
SYSREF: 2 pulses @ 1/32 DACCLK frequency
Interpolation: 1
Serdes linerate: 2970Mbps
K: 32
serdes clk div: 1
jesd clk div: 1
SerDes rate: 1/4
SerDes MPY: 20
Here is the DAC385J84 configuration sequence:
bool DAC_init(void)
{
bool allOK = TRUE;
alt_u16 reg_value;
// Step numbers are from Kang Hsia's adaptation of slaa696
// Step 4, toggle DAC_RESETB (manual sec 8.3 Step 5)
system_control_write(DEV, DEV_DAC_TXENABLE, FALSE); // make sure TX is disabled until after JESD_init()
system_control_write(DEV, DEV_DAC_RESET, TRUE); // toggle RESETb (inverted on the way to the pin in top-level verilog)
usleep(1); // ensure RESETb pulse width exceeds 25ns minimum
system_control_write(DEV, DEV_DAC_RESET, FALSE);
Send_DAC(0x02,0x2083); // [15:14] 16-bit DAC width, [13] zero invalid data, [7] enable SPI_DAC_SDO, [1] 2's complement, [0] = assert soft reset
Send_DAC(0x02,0x2082); // [15:14] 16-bit DAC width, [13] zero invalid data, [7] enable SPI_DAC_SDO, [1] 2's complement, [0] = clr soft reset
// Step 5, confirm PoR presets have loaded
reg_value = Read_DAC(0x7f);
if ((bit_field(reg_value, DAC_LOAD_STATUS, DAC_LOAD_STATUS) == 1)
&& (bit_field(reg_value, DAC_VENDOR_HI, DAC_VENDOR_LO) == DAC_VENDOR_ID)
&& (bit_field(reg_value, DAC_VERSION_HI, DAC_VERSION_LO) == DAC_VERSION_ID)) {
rubydbprint(DBSS_DAC,"DAC chip fusefarm loaded correctly.\r\n");
} else {
allOK = FALSE;
rubydbprint(DBSS_DAC,"DAC chip fusefarm failed to load, reading back error code %x, vendor code %u, version %u.\r\n",
bit_field(reg_value, DAC_ERR_CODE_HI, DAC_ERR_CODE_LO),
bit_field(reg_value, DAC_VENDOR_HI, DAC_VENDOR_LO),
bit_field(reg_value, DAC_VERSION_HI, DAC_VERSION_LO));
}
// Step 6, "program per application's need"
// Step 6.0 housekeeping not addressed in Kang's sequence
Send_DAC(0x4A,0x0f1e); // Hold the JESD state machine in reset during programming (not per Kang's sequence, but Abaco does this as the very 1st thing)
Send_DAC(0x04,0xf0f0); // [11:8] are lanes 3..0 SerDes lane errors and [3:0] are lanes 3..0 FIFO flags; mask the others
Send_DAC(0x05,0xef05); // mask SYSREF errors from unused links, (unused) PAP alarms, SerDes block 1, and unused DAC PLL
Send_DAC(0x06,0xffff); // mask all short tests and LOS alarms
Send_DAC(0x23,0xffff); // allow all subsystems to sleep when SLEEP is asserted (for live shutdown)
// Step 6.1, Clocking Configuration Registers: DAC PLL (unused): regs 0x31 to 0x33
Send_DAC(0x1A,0x0020); // [5] DAC PLL sleep
Send_DAC(0x24,0x0000); // [6:4] = 0 SYSREF pulses don't reset dividers, because DAC PLL is unused
Send_DAC(0x31,0x1000); // [12] = 1 PLL reset; [10] = 0 PLL disable (in favor of direct DACCLK to the core)
// Step 6.2, SerDes PLL and PMAs regs 0x3B to 0x3F
Send_DAC(0x3B,0x0000); // [15] bypass internal PLL, use DACCLK input as SerDes refclk; [14:11] divide refclk by 1
// Send_DAC(0x3C,0x18a0); // SerDes PLL [15] !EN div by 5 output; [12:11] high loop bandwidth; [10] !sleep; [9] = 0 high VCO freq. range; [8:1] MPY = 20
// Send_DAC(0x3C,0x00a0); // SerDes PLL [15] !EN div by 5 output; [12:11] medium loop bandwidth, per Abaco; [10] !sleep; [9] = 0 high VCO freq. range; [8:1] MPY = 20
Send_DAC(0x3C,0x10a0); // SerDes PLL [15] !EN div by 5 output; [12:11] low loop bandwidth, for poor clock; [10] !sleep; [9] = 0 high VCO freq. range; [8:1] MPY = 20
Send_DAC(0x3D,0x0088); // [7] EN offset compensation; [5] no EQ boost; [4:3] = 1 adaptive EQ; [2:0] = 0 for CDR algorithm 0
Send_DAC(0x3E,0x0148); // [15:13]: no LOS alarm in any lane; [10:8]: AC coupled termination; [6:5]: 1/4 rate; [4:2]: 20b 8b10b double-word width; [1]: !Sleep RX ccts
// Step 6.3, JESD204B parameters incl configuring JESD RX FSM regs 0x46 to 0x62
// Leave the Lane ID per PoR, at the risk of lane configuration errors, to avoid potentially confusing the receiver
// Send_DAC(0x46,0x0000); // set Lane ID to 0 for lanes 0 .. 2, to avoid JESD ILAS errors
// Send_DAC(0x47,0x010a); // set Lane ID to 0 for lane 3
Send_DAC(0x25,0x0000); // JESD clock rate == input clock rate
Send_DAC(0x4B,0x1f01); // both coded N+1: [12:8] elastic read buffer depth = 32 (== K); [7:0] 2 octets per SerDes frame (== F)
Send_DAC(0x4C,0x1f03); // both coded N+1: [12:8] JESD K = 32; [4:0] L = 4 lanes in use
Send_DAC(0x4D,0x0300); // both coded N+1: [15:8] M = 4 converters per link; [4:0] selects S = 1 sample per frame (@ 2 octets, that means 16b samples)
Send_DAC(0x4F,0x1c41); // [7] = 0 do not match a specific symbol, begin buffering the 1st non-K after ILAS completes; [0] = 1 enable JESD comma align
Send_DAC(0x51,0x00df); // [7:0] enable any of the errors to generate a sync request, except link configuration
Send_DAC(0x52,0x00df); // [7:0] enable any of the errors to count, except link configuration
Send_DAC(0x61,0x0001); // only link0 drives SYNCb
// Step 6.4, DSP blocks, all of the substantive ones bypassed.
// Step 6.4.a regs 0x00 to 0x02
Send_DAC(0x22,0x1be4); // [15:8] implement direct input correspondence; [7:0] implement output swizzle
Send_DAC(0x00,0x0018); // [15:12] disable analog functions; [11:8] interpolation = 1; [4:3] enable alarm out @ positive polarity
// [7],[5] don't disable outputs on alarm; [6] don't sum datapaths; [2:0] disable power amp protection & inv sync filters
// Reg 0x02 was initialised at the outset rather than here, to provide for SPI readback
// Step 6.4.b respective coefficients from regs 0x08 to 0x19
// ... all of the blocks controlled by these coefficients are bypassed
// Step 6.4.c DSP block initializers are set from regs 0x1E to 0x20
// ... all of the blocks controlled by these coefficients are bypassed
// Step 7, Verify SerDes PLL Lock Status
usleep(1000); // wait before testing PLL lock (Kang's lock acquisition interval calculation at the bottom of Step 7 implies ~20usec for 148.5MHz)
Send_DAC(0x6C,0x0000); // clear alarms
usleep(200);
reg_value = Read_DAC(0x6C); // test alarm_rw0_pll, confirm SERDES PLL is locked
if (bit_field(reg_value, DAC_SERDES_PLL_LOCK_ALARM, DAC_SERDES_PLL_LOCK_ALARM)) { // DAC_SERDES_PLL_LOCK_ALARM is position [3]
printf("DAC chip SerDes PLL is out of lock.\r\n");
allOK = FALSE;
}
else printf("DAC chip SerDes PLL is locked to DACCLK.\r\n");
// The remaining Steps initialisation Steps appear in DAC_JESD_arm() and DAC_JESD_disarm()
return allOK;
} // DAC_init
Would you kindly advise as to why the SerDes PLL is not locking?
Hopeful thanks --todd