Hello Analog Devices team,
I am using an AD9528BCPZ as a clock distribution device in a system with AD7768 ADCs. The MCU is an STM32F446ZET6, and the firmware is generated in STM32CubeIDE. I have two AD9528BCPZ for one of is MCLK distribution and the other one is for SYNC distribution.
My clock distribution requirement is:
AD9528:
- Generate/distribute 32 MHz MCLK to all ADC channels
- Generate two successive SYSREF/SYNC pulses for AD7768 synchronization
- The SYSREF/SYNC pulses must remain phase-deterministic with respect to the distributed 32 MHz MCLK
The system is very phase-sensitive; we are working at picosecond-level timing, so I cannot generate the sync pulses from an unrelated MCU GPIO or another asynchronous source. The sync pulse must remain inside the AD9528 clock/SYSREF timing domain.
The problem is the polarity of the sync signal required by the AD7768 side.
At the moment, the AD9528 internal SYSREF N-shot generator gives this waveform:
Current AD9528 SYSREF output:
LOW idle ________________|¯¯¯¯¯¯¯¯|________|¯¯¯¯¯¯¯¯|________________
However, the AD7768 synchronization input in my system needs an active-low sync pulse, so I need the opposite polarity:
Required waveform:
HIGH idle ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|________|¯¯¯¯¯¯¯¯|________|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Important constraints:
1. I cannot solve this by swapping LVDS P/N lines in hardware.
2. I cannot generate the pulse directly from the STM32 GPIO, because that makes the sync timing independent from the AD9528 MCLK/SYSREF domain.
3. I need two successive pulses.
4. The sync pulse must remain deterministic relative to the AD9528 32 MHz clock outputs.
I also tried changing the AD9528 output channel source selection. For example, I tested the source option that appears to use SYSREF retimed by inverted PLL1 output. But it works like LOW idle mode.
My master and sync profile:
const ad9528_reg_t ad9528_1_master_profile[] = {
{ AD9528_PLL1_REF_A_DIVIDER, 1u },
{ AD9528_PLL1_REF_B_DIVIDER, 1u },
{ AD9528_PLL1_FEEDBACK_DIVIDER, 5u },
{ AD9528_PLL1_CHARGE_PUMP_CTRL,
AD9528_PLL1_CHARGE_PUMP_AUTO_TRISTATE_DIS |
AD9528_PLL1_CHARGE_PUMP_MODE_NORMAL |
AD9528_PLL1_CHARGE_PUMP_CURRENT_nA(5000u) },
{ AD9528_PLL1_CTRL,
AD9528_PLL1_OSC_CTRL_FAIL_VCC_BY2_EN |
AD9528_PLL1_REF_MODE(REF_MODE_SELECT_REFA) |
AD9528_PLL1_REFA_DIFF_RCV_EN |
AD9528_PLL1_REFA_RCV_EN |
AD9528_PLL1_OSC_IN_DIFF_EN },
{ AD9528_PLL2_CHARGE_PUMP,
AD9528_PLL2_CHARGE_PUMP_CURRENT_nA(805000u) },
{ AD9528_PLL2_FEEDBACK_DIVIDER_AB,
AD9528_PLL2_FB_NDIV_A_CNT(0u) |
AD9528_PLL2_FB_NDIV_B_CNT(10u) },
{ AD9528_PLL2_CTRL,
AD9528_PLL2_CHARGE_PUMP_MODE_NORMAL },
{ AD9528_PLL2_VCO_CTRL, 0u },
{ AD9528_PLL2_VCO_DIVIDER,
AD9528_PLL2_VCO_DIV_M1(5u) },
{ AD9528_PLL2_LOOP_FILTER_CTRL, 0u },
{ AD9528_PLL2_R1_DIVIDER,
AD9528_PLL2_R1_DIV(1u) },
{ AD9528_PLL2_N2_DIVIDER,
AD9528_PLL2_N2_DIV(8u) },
{ AD9528_CHANNEL_OUTPUT(0), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(1), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(2), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(3), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(4), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(5), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(6), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(7), MCLK_32_CH },
{ AD9528_CHANNEL_OUTPUT(8), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(9), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(10), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(11), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(12), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(13), REF16_CH },
{ AD9528_CHANNEL_SYNC_IGNORE, 0u },
{ AD9528_SYSREF_K_DIVIDER,
AD9528_SYSREF_K_DIV(512u) },
{ AD9528_SYSREF_CTRL,
AD9528_SYSREF_SOURCE(SYSREF_SRC_INTERNAL) |
AD9528_SYSREF_PATTERN_MODE(SYSREF_PATTERN_NSHOT) |
AD9528_SYSREF_NSHOT_MODE(SYSREF_NSHOT_2_PULSES) },
{ AD9528_CHANNEL_PD_EN,
AD9528_CHANNEL_PD_MASK(0x1F00u) },
{ AD9528_STAT_MON0, AD9528_STAT_PLL1_LD },
{ AD9528_STAT_MON1, AD9528_STAT_PLL2_LD },
{ AD9528_STAT_PIN_EN, AD9528_STAT0_PIN_EN | AD9528_STAT1_PIN_EN },
};
const ad9528_reg_t ad9528_2_sync_profile[] = {
{ AD9528_PLL1_REF_A_DIVIDER, 1u },
{ AD9528_PLL1_REF_B_DIVIDER, 1u },
{ AD9528_PLL1_FEEDBACK_DIVIDER, 1u },
{ AD9528_PLL1_CHARGE_PUMP_CTRL,
AD9528_PLL1_CHARGE_PUMP_TRISTATE },
{ AD9528_PLL1_CTRL,
AD9528_PLL1_SOURCE_VCXO |
AD9528_PLL1_FEEDBACK_BYPASS_EN |
AD9528_PLL1_REFB_BYPASS_EN |
AD9528_PLL1_REFA_BYPASS_EN |
AD9528_PLL1_OSC_IN_DIFF_EN },
{ AD9528_PLL2_CHARGE_PUMP,
AD9528_PLL2_CHARGE_PUMP_CURRENT_nA(805000u) },
{ AD9528_PLL2_FEEDBACK_DIVIDER_AB,
AD9528_PLL2_FB_NDIV_A_CNT(2u) |
AD9528_PLL2_FB_NDIV_B_CNT(62u) },
{ AD9528_PLL2_CTRL,
AD9528_PLL2_CHARGE_PUMP_MODE_NORMAL },
{ AD9528_PLL2_VCO_CTRL, 0u },
{ AD9528_PLL2_VCO_DIVIDER,
AD9528_PLL2_VCO_DIV_M1(5u) },
{ AD9528_PLL2_LOOP_FILTER_CTRL, 0u },
{ AD9528_PLL2_R1_DIVIDER,
AD9528_PLL2_R1_DIV(1u) },
{ AD9528_PLL2_N2_DIVIDER,
AD9528_PLL2_N2_DIV(50u) },
{ AD9528_CHANNEL_OUTPUT(0), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(1), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(2), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(3), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(4), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(5), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(6), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(7), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(8), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(9), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(10), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(11), SYSREF_CH },
{ AD9528_CHANNEL_OUTPUT(12), OFF_CH },
{ AD9528_CHANNEL_OUTPUT(13), OFF_CH },
{ AD9528_CHANNEL_SYNC_IGNORE, 0u },
{ AD9528_SYSREF_K_DIVIDER, AD9528_SYSREF_K_DIV(AD9528_SYNC_PULSE_WIDTH) },
{ AD9528_SYSREF_CTRL,
AD9528_SYSREF_SOURCE(SYSREF_SRC_INTERNAL) |
AD9528_SYSREF_PATTERN_MODE(SYSREF_PATTERN_NSHOT) |
AD9528_SYSREF_NSHOT_MODE(SYSREF_NSHOT_2_PULSES) |
AD9528_SYSREF_REQUEST_BY_PIN |
AD9528_SYSREF_PATTERN_TRIGGER_CTRL(SYSREF_EDGE_RISING) },
{ AD9528_PD_EN,
AD9528_PD_PLL1 | 0x10u }, /* 0x10 = bias normal, bit2 = PLL1 PD */
{ AD9528_CHANNEL_PD_EN,
AD9528_CHANNEL_PD_MASK(0x300Fu) },
{ AD9528_STAT_MON0, AD9528_STAT_PLL2_LD },
{ AD9528_STAT_MON1, AD9528_STAT_VCXO },
{ AD9528_STAT_PIN_EN, AD9528_STAT0_PIN_EN | AD9528_STAT1_PIN_EN },
};
Any clarification would be very helpful, especially whether this is fundamentally impossible in AD9528 or if there is a correct register-level configuration that I am missing.
Best regards.
