AD9082
Recommended for New Designs
The AD9082 mixed signal front-end (MxFE®) is a highly integrated device with a 16-bit, 12 GSPS maximum sample rate, RF digital-to-analog converter (DAC...
Datasheet
AD9082 on Analog.com
HMC7044
Recommended for New Designs
The HMC7044 is a high performance, dual-loop, integer-N jitter attenuator capable of performing reference selection and generation of ultralow phase noise...
Datasheet
HMC7044 on Analog.com
AD9988
Recommended for New Designs
The AD9988 is a highly integrated device with four 16-bit, 12 GSPS maximum sample rate, RF digital-to-analog converter (DAC) cores, and four 12-bit, 4...
Datasheet
AD9988 on Analog.com
I need ADC sampling complex signals, and output results being separated according to I and Q. However, the results looks like the real signals and not complex signals.When I analysis digital signals from ADC, I find half of the data are duplicate. For example, sample1, sample2, sample3, sample4, sample1, sample2, sample3, sample4, sample5, sample6, sample7, sample8, sample5, sample6, sample7, sample8,.......
There must be an error in somwhere of the configuration code,and I have no idea to figure out.
The sample rate of ADC is 4800MSPS, dual links.And here are some configuration informations.
JMODE 13
L 4 M 2 F 1 S 1 HD 1 K 256 N/N' 16 Subclass 1 jesd204c
CDDC 2 FDDC 0
I use API Device Drivers to write configuration,and the main code is as follows.
/*============= I N C L U D E S ============*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "xil_printf.h"
#include "xil_io.h"
#include "xil_types.h"
#include "adi_cms_api_common.h"
#include "adi_ad9988.h"
#include "adi_ad9988_config.h"
#include "adi_ad9988_hal.h"
//#include "adi_ads9.h"
//#include "adi_hmc7044.h"
#include "adi_ad7175.h"
//#include "ads9.h"
#include "ad9988_app_helper.h"
#include "mxfe_ad9082.h"
/*============= M A C R O S====================*/
/*============= D A T A ====================*/
/*Eval Application Usecase Datapath Configuration*/
/*Refer to uc_settings.c for list of uc definitions*/
/*Clock Scheme Sources and Frequencies*/
extern uint64_t clk_hz[][4];
/* Transmit Datapath Configuration*/
extern uint8_t tx_dac_chan_xbar[][4]; /*Transmit Channel and Main DAC Datapaths*/
extern int8_t tx_chan_gain[][8]; /*Transmit Channel Gain DAC Datapaths*/
extern int64_t tx_main_shift[][4]; /*Transmit Main/Coarse DUC NCO Frequency Setting*/
extern int64_t tx_chan_shift[][8]; /*Transmit Channel/Fine DUC NCO Frequency Setting*/
extern uint8_t tx_interp[][2]; /*Trnacmit Data Interpolation for Coarse/Fine DUCs */
extern uint8_t rx_cddc_select[];
extern uint8_t rx_fddc_select[];
extern int64_t rx_cddc_shift[][4];
extern int64_t rx_fddc_shift[][8];
extern uint8_t rx_cddc_dcm[][4];
extern uint8_t rx_fddc_dcm[][8];
extern uint8_t rx_cddc_c2r[][4];
extern uint8_t rx_fddc_c2r[8];
extern uint8_t jtx_logiclane_mapping_pe_brd[2][8];
extern uint8_t jtx_logiclane_mapping_ce_brd[2][8];
extern adi_ad9988_jtx_conv_sel_t jtx_conv_sel[][2];
extern adi_cms_jesd_param_t jrx_param[];
extern adi_cms_jesd_param_t jtx_param[][2];
extern uint8_t jtx_chip_dcm[][2];
/*============= C O D E ====================*/
int32_t main(int argc, char *argv[])
{
int32_t err, i, uc = 0, use_7044 = 0, use_ce_brd = 1;
uint64_t app_jrx_lane_rate = 0, app_jtx_lane_rate[2] = {0};
uint8_t k, j, en_ad7175 = 0;
float line_rate_refclk_ratio = 0.0;
uint16_t ad9988_jrx_link_status[2];
uint8_t ad9988_jrx_tpl_link_status[2];
uint32_t da_fsc[4]={0};
uint8_t setup_risk_violation,hold_risk_violation;
uint8_t lmfc_align_err,sysref_error_window;
uint32_t reg_dac_msg_out =0;
int ad9082_enable;
int16_t rb_temp_max,rb_temp_min;
adi_cms_chip_id_t chip_id;
/* determine use case */
if (argc > 1) {
uc = atoi(argv[1]);
}
/* determine if using 7044 or not */
if (argc > 2) {
use_7044 = atoi(argv[2]);
}
/* determine if using ce board or pe board */
if (argc > 3) {
use_ce_brd = atoi(argv[3]);
if (use_ce_brd <= 0 && use_7044 > 0){
printf("PE Board is not compatible with HMC7044 Clock.");
return API_CMS_ERROR_OK;
}
}
/* connect to platform */
adi_ad9988_device_t ad9988_dev = {
.hal_info = {
.sdo = SPI_SDO,
.msb = SPI_MSB_FIRST,
.addr_inc = SPI_ADDR_INC_AUTO,
.log_write = 0,
.delay_us = ad9082_wait_us,
.spi_xfer = 0,
.reset_pin_ctrl = 0,
},
.serdes_info = {
.ser_settings = { /* ad9988 jtx */
.lane_settings = {
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
{.swing_setting = AD9988_SER_SWING_850,.pre_emp_setting = AD9988_SER_PRE_EMP_0DB,.post_emp_setting = AD9988_SER_POST_EMP_0DB},
},
.invert_mask = 0x00,
.lane_mapping = { { 0,1,2,3,4,5,6,7 }, { 4,5,6,7,0,1,2,3 } }, /* link0, link1 */
},
.des_settings = { /* ad9988 jrx */
.boost_mask = 0xff,
.invert_mask = 0x00,
.ctle_filter = { 2, 2, 2, 2, 2, 2, 2, 2 },
.cal_mode = AD9988_CAL_MODE_RUN,
.ctle_coeffs = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, /* CTLE 1-4 for lanes 0-7 */
.lane_mapping = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 7, 6, 5, 4, 0, 1, 2, 3 } }, /* link0, link1 x=l when <x means use lane ,when =8 means not use*/
}
},
.clk_info = {
.sysref_mode = SYSREF_CONT,
}
};
if (use_ce_brd <= 0){
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 8; j++){
ad9988_dev.serdes_info.ser_settings.lane_mapping[i][j] = jtx_logiclane_mapping_pe_brd[i][j];
}
}
}
printf("APP: Configure Usecase:%d, Tx Path: DAC Clk: %lld, JESD Rx Mode: %d & Rx Path: ADC CLK: %lld, Jesdmode Tx Mode: %d \r\n",
uc, clk_hz[uc][2], jrx_param[uc].jesd_mode_id, clk_hz[uc][3], jtx_param[uc][0].jesd_mode_id);
{/* Do Hard Rest of Devices*/
adi_ad9988_device_reset(&ad9988_dev, AD9988_HARD_RESET);
}
{
#if !defined(AD9207_ID) && !defined(AD9209_ID)
app_calc_tx_lane_rate(clk_hz[uc], &jrx_param[uc], tx_interp[uc], &app_jrx_lane_rate);
#endif
#if !defined(AD9177_ID)
app_calc_rx_lane_rate(clk_hz[uc], jtx_param[uc], jtx_chip_dcm[uc], app_jtx_lane_rate);
#endif
printf("APP: Tx Lane Rate : %llu Rx0 Lane Rate : %llu Rx1 Lane Rate : %llu \r\n", app_jrx_lane_rate, app_jtx_lane_rate[0], app_jtx_lane_rate[1]);
}
/* AD9988 Device Data Path Configuration Sequenece
* Do AD9988 Device RESET, adi_ad9988_device_reset
* Do AD9988 Device Initialization: adi_ad9988_device_init
* Do AD9988 Device Clocks Config (REF CLK, DAC CLK, ADC Clock):adi_ad9988_device_clk_config_set
* Do AD9988 Device TX Datapath (JESD RX to DAC) Primary Configuration: adi_ad9988_device_startup_tx
* Do AD9988 Device Tx Datapath Secondary Configuration as per specific UC requirements
* eg TX Gain APIs
* - adi_ad9988_dac_duc_nco_gains_set
* TX Datapath Customization API:
* -adi_ad9988_dac_modulation_mux_mode_set
* -adi_ad9988_dac_xbar_set
* TX Test Modes APIs:
* -adi_ad9988_device_startup_nco_test
* Do AD9988 Device RX Datapath (ADC to JESD TX) Primary Configuration: adi_ad9988_device_startup_rx
* Do AD9988 Device Rx Datapath Secondary Configuration as per specific UC requirements
* eg: RX Gain APIs:
* - adi_ad9988_adc_ddc_fine_gain_set
* RX Datapath Customization APIs:
* - adi_ad9988_adc_nyquist_zone_set
* - adi_ad9988_adc_xbar_set
* RX Test Mode APIs:
* - adi_ad9988_jesd_loopback_mode_set
* - adi_ad9988_adc_ddc_coarse_nco_mode_set
*
*/
{
uint8_t adc_cddc_xbar, cddc_fddc_xbar;
uint16_t phase = 0;
printf("APP: Configure ad9988 Device\n");
/* reset ad9988 */
if (err = adi_ad9988_device_reset(&ad9988_dev, AD9988_SOFT_RESET), err != API_CMS_ERROR_OK) {
printf("APP: ad9988 Initialisation Error\n");
return err;
}
/* init ad9988 */
if (err = adi_ad9988_device_init(&ad9988_dev), err != API_CMS_ERROR_OK) {
printf("APP: ad9988 Initialisation Error\n");
return err;
}
adi_ad9988_device_chip_id_get(&ad9988_dev, &chip_id);
if(chip_id.prod_id == 0x9082){
ad9082_enable = 1;
}
/* setup ad9988 clock */
err = adi_ad9988_device_clk_config_set(&ad9988_dev, clk_hz[uc][2], clk_hz[uc][3], clk_hz[uc][0]);
uint8_t ad9988_pll_locked = 0;
adi_ad9988_device_clk_pll_lock_status_get(&ad9988_dev, &ad9988_pll_locked);
if (ad9988_pll_locked == 0x3) {
printf("APP: ad9988 PLL LOCKED\n");
}
if (err != API_CMS_ERROR_OK) {
printf("APP: Clock Configuration error\n");
return err;
}
#if !defined(AD9207_ID) && !defined(AD9209_ID)
uc = 0;
/* start ad9988 tx */
if (err = adi_ad9988_device_startup_tx(&ad9988_dev, tx_interp[uc][0], tx_interp[uc][1], tx_dac_chan_xbar[uc],
tx_main_shift[uc], tx_chan_shift[uc], &jrx_param[uc]), err != API_CMS_ERROR_OK) {
printf("APP: ad9988 Tx Path Configuration Error \n");
if (err == API_CMS_ERROR_JESD_PLL_NOT_LOCKED) {
printf("APP: ad9988 Tx Path Configuration JESD PLL Not Locked \n");
}
return err;
}
/* Setup ad9988 tx channel gain */
uint16_t tx_chan_gains[8];
for (i = 0; i < 8; i++)
tx_chan_gains[i] = (uint16_t)(pow(2, 11) * pow(10, (tx_chan_gain[uc][i]) / 20.0));
if (err = adi_ad9988_dac_duc_nco_gains_set(&ad9988_dev, tx_chan_gains), err != API_CMS_ERROR_OK)
return err;
#endif
/*Configure Primary Rx Datapath Settings*/
if (err = adi_ad9988_device_startup_rx(&ad9988_dev, rx_cddc_select[uc], rx_fddc_select[uc], rx_cddc_shift[uc], rx_fddc_shift[uc],
rx_cddc_dcm[uc], rx_fddc_dcm[uc], rx_cddc_c2r[uc], rx_fddc_c2r, jtx_param[uc], jtx_conv_sel[uc]), err != API_CMS_ERROR_OK) {
printf("APP: ad9988 Rx Path Configuration Error \n");
return err;
}
/* Set gain settings as per Application Usecase */
if (err = adi_ad9988_adc_ddc_fine_gain_set(&ad9988_dev, rx_fddc_select[uc], 1), err != API_CMS_ERROR_OK)
return err;
/*Override NCO Mode*/
if (err = adi_ad9988_adc_ddc_coarse_nco_mode_set(&ad9988_dev, rx_cddc_select[uc], AD9988_ADC_NCO_ZIF), err != API_CMS_ERROR_OK)
return err;
/* Set ADC Nyquist Zone as per Application Usecase for ADC optimal Background Cal Operation*/
/*ADC Test Test Mode*/
if (err = adi_ad9988_adc_nyquist_zone_set(&ad9988_dev, AD9988_ADC_ALL, AD9988_ADC_NYQUIST_ZONE_EVEN), err != API_CMS_ERROR_OK)
return err;
/* Configure Synchronization Options as per Application Use-case*/
/* By Default Application uses Subclass 0 and Internal Sysref Synchronization*/
/* Note 21/26/27 Are examples of Subclass 1*/
printf("APP: JESD RX Synchronization Mode: %s\n", ((jrx_param[uc].jesd_subclass == JESD_SUBCLASS_1) ? "JESD_SUBCLASS_1" : "JESD_SUBCLASS_0"));
/* Configure Sysref Receiver and Input mode */
if (err = adi_ad9988_sync_sysref_input_config_set(&ad9988_dev, COUPLING_DC, SIGNAL_LVPECL, 0, 0), err != API_CMS_ERROR_OK)
return err;
/* Configure cddc nco sync */
if (err = adi_ad9988_adc_ddc_coarse_sync_enable_set(&ad9988_dev, AD9988_ADC_CDDC_ALL, 1), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_ddc_coarse_sync_next_set(&ad9988_dev, AD9988_ADC_CDDC_ALL, 1), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_ddc_coarse_trig_nco_reset_enable_set(&ad9988_dev, AD9988_ADC_CDDC_ALL, 0), err != API_CMS_ERROR_OK)
return err;
/* Perform oneshot sync */
if (err = adi_ad9988_jesd_oneshot_sync(&ad9988_dev, 1), err != API_CMS_ERROR_OK){
if (err == API_CMS_ERROR_JESD_SYNC_NOT_DONE) {
printf("APP: JESD Oneshot Synchronization Not Completed\n");
}
return err;
}
if (err = adi_ad9988_jesd_sysref_monitor_phase_get(&ad9988_dev, &phase), err != API_CMS_ERROR_OK)
return err;
printf("APP: Phase offset between incoming SYSREF and internal LMFC/LEMC: %d DAC clock units\n", phase);
/* SYSTEM Link Bring Up Sequenece
* Check AD9988 JESD PLL Lock Status
* Enable AD9988 JESD Rx/ JESD TX Links
* Ensure FPGA JESD RX/ JESD TX Links are configured
* Ensure FPGA is transmitting Data
* Toggle AD9988 JESD RX Links Enable
* Run AD9988 JESD RX 204C Calibration if Lane Rate is above Threshold AD9988_JESDRX_204C_CAL_THRESH
* Toggle AD9988 JESD RX Links Enable
* Check Link Status after short period time
*/
/* Check JESD PLL LOCK Status */
uint8_t uc_jesd_pll_status = 0x00;
err = adi_ad9988_jesd_pll_lock_status_get(&ad9988_dev, &uc_jesd_pll_status);
printf("APP: ad9988 JESD PLL lock Status: %s : %s\n", (uc_jesd_pll_status ? "LOCKED" : "NOT LOCKED"), (uc_jesd_pll_status ? "Enabling Links" : "Exiting"));
if (err != API_CMS_ERROR_OK) {
return err;
}
#if !defined(AD9177_ID)
/* enable ad9988 Rx Path: JESD Tx Link links */
if (err = adi_ad9988_jesd_tx_link_enable_set(&ad9988_dev, (jtx_param[uc][0].jesd_duallink > 0) ? AD9988_LINK_ALL : AD9988_LINK_0, 1), err != API_CMS_ERROR_OK)
return err;
#endif
#if !defined(AD9207_ID) && !defined(AD9209_ID)
/* enable ad9988 Tx Path: JESD Rx Link links */
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, (jrx_param[uc].jesd_duallink > 0) ? AD9988_LINK_ALL : AD9988_LINK_0, 1), err != API_CMS_ERROR_OK)
return err;
#endif
/*Ensure FPGA JESD RX/ JESD TX Links are configured*/
/*wait fpga jesd axi cfg done*/
#if !defined(AD9207_ID) && !defined(AD9209_ID)
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, AD9988_LINK_ALL, 0), err != API_CMS_ERROR_OK)
return err;
#endif
#if !defined(AD9207_ID) && !defined(AD9209_ID)
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, (jrx_param[uc].jesd_duallink > 0) ? AD9988_LINK_ALL : AD9988_LINK_0, 1), err != API_CMS_ERROR_OK)
return err;
#endif
/* calibrate jrx when lane rate is high for 204c */
printf("APP: Run JESD RX 204C Calibration & Enable TX Path Links\n");
#if !defined(AD9207_ID) && !defined(AD9209_ID)
char ctle_file[] = "ctle_coeffs";
if ((jrx_param[uc].jesd_l > 0) && (jrx_param[uc].jesd_jesdv == 2) && ((clk_hz[uc][1] * 66) > AD9988_JESDRX_204C_CAL_THRESH)) {
if (ad9988_dev.serdes_info.des_settings.cal_mode == AD9988_CAL_MODE_BYPASS) {
app_cal_ctle_manual_config_load(&ad9988_dev, ctle_file);
}
if (err = adi_ad9988_jesd_rx_calibrate_204c(&ad9988_dev, 1, 0x00, (ad9988_dev.serdes_info.des_settings.cal_mode == AD9988_CAL_MODE_RUN_AND_SAVE) ? 0 : 1), err != API_CMS_ERROR_OK) {
printf("APP: ad9988 JESD RX Calibration Error\n");
return err;
}
if (ad9988_dev.serdes_info.des_settings.cal_mode == AD9988_CAL_MODE_RUN_AND_SAVE) {
app_cal_ctle_manual_config_save(&ad9988_dev, ctle_file);
}
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, AD9988_LINK_ALL, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, (jrx_param[uc].jesd_duallink > 0) ? AD9988_LINK_ALL : AD9988_LINK_0, 1), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, AD9988_LINK_ALL, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_jesd_rx_link_enable_set(&ad9988_dev, (jrx_param[uc].jesd_duallink > 0) ? AD9988_LINK_ALL : AD9988_LINK_0, 1), err != API_CMS_ERROR_OK)
return err;
}
#endif
#if !defined(AD9177_ID)
/* TDD Power Savings*/
if (err = adi_ad9988_adc_adc0_rxen_pwdn_ctrl_set(&ad9988_dev, 1, 0, 1, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_adc1_rxen_pwdn_ctrl_set(&ad9988_dev, 1, 0, 1, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_adc2_rxen_pwdn_ctrl_set(&ad9988_dev, 0, 1, 0, 1), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_adc3_rxen_pwdn_ctrl_set(&ad9988_dev, 0, 1, 0, 1), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxen0_sel_set(&ad9988_dev, 0, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxen0_ctrl_set(&ad9988_dev, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxen1_sel_set(&ad9988_dev, 0, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxen1_ctrl_set(&ad9988_dev, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxengp0_sel_set(&ad9988_dev, 0, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxengp0_ctrl_set(&ad9988_dev, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxengp1_sel_set(&ad9988_dev, 0, 0, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
if (err = adi_ad9988_adc_rxengp1_ctrl_set(&ad9988_dev, 0, 0, 0), err != API_CMS_ERROR_OK)
return err;
#endif
/* wait some times */
err = adi_ad9988_hal_delay_us(&ad9988_dev, 100000);
AD9988_ERROR_RETURN(err);
/* check link status */
if (err = app_show_link_status(&ad9988_dev), err != API_CMS_ERROR_OK)
return err;
}
/*output dac status */
adi_ad9988_jesd_rx_link_status_get(&ad9988_dev, AD9988_LINK_0 , &ad9988_jrx_link_status[0]);
adi_ad9988_jesd_rx_link_status_get(&ad9988_dev, AD9988_LINK_1 , &ad9988_jrx_link_status[1]);
adi_ad9988_jesd_rx_link_select_set(&ad9988_dev, AD9988_LINK_0);
adi_ad9988_device_spi_register_set(&ad9988_dev, 0x04a0, &ad9988_jrx_tpl_link_status[0]);
adi_ad9988_jesd_rx_link_select_set(&ad9988_dev, AD9988_LINK_1);
adi_ad9988_device_spi_register_set(&ad9988_dev, 0x04a0, &ad9988_jrx_tpl_link_status[1]);
adi_ad9988_jesd_sysref_setup_hold_get(&ad9988_dev, &setup_risk_violation, &hold_risk_violation);
printf("setup_risk_violation = 0x%.2x, hold_risk_violation =0x%.2x\n", setup_risk_violation, hold_risk_violation);
adi_ad9988_jesd_sysref_monitor_lmfc_align_error_get(&ad9988_dev, &lmfc_align_err);
adi_ad9988_jesd_sysref_monitor_lmfc_align_threshold_set(&ad9988_dev, &sysref_error_window);
printf("SYSREF_WITHIN_LMFC_ERRWINDOW: %.1x, SYSREF_ERR_WINDOW: 0x%.2x\n", lmfc_align_err, sysref_error_window);
adi_ad9988_device_get_temperature(&ad9988_dev, &rb_temp_max, &rb_temp_min);
printf("\n");
return API_CMS_ERROR_OK;
}
The us_setting.c is as as follows.
/*============= I N C L U D E S ============*/
#include <stdio.h>
#include <unistd.h>
#include "adi_ad9988.h"
/*============= D A T A ====================*/
/* Usecase Frequency Scheme Settings
* This array list the desired clocks required for the usecase.
* For each usecase an array of depth 4 provides the frequecy in Hz for the following clocks
* As this application targets the Txfe/MxFE evaluation board, that my have various XTAL as reference to the HMC7044.
* The comments following the usecase entry will indicate if the scheme can be used with the target hardware.
* The Comments also provide the expected lane rate of the usecase.
* clk_hz["usecase"][0] Txfe/MxFE Device reference Clock (dev_ref), if not using on chip pll, this should be equal to the dac_clk
* clk_hz["usecase"][1] The value of the reference clock to the ADS9 FPGA JESD Blocks, This is not used by MxFE/TxFE API. (204C lane rate/66) or (204B lane rate/20)
* clk_hz["usecase"][2] The MxFE TX data path DAC sampling clock (dac_clk) as per the desired usecase
* clk_hz["usecase"][3] The MxFE Rx data path ADC aampling clock (adc_clk) as per the desired usecase
* Notes:
* The Example Application will use adi_ad9988_device_clk_config_set to configure the MxFE/TxFE based on th dev_ref, dac_clk, and adc_clk.
* If the on-chip PLL feature of MxFe/Txfe is not required dev_ref and dac_clk should be set to the same value.
* If on chip PLL is required, then based on the applied dev_ref clock and the desired dac_clk the API will configure the onchip -pll appropriately
* The API will also configure the chip to generate the desired adc_clk based on the dac_clk.
*
*/
uint64_t clk_hz[][4] = {
/*dev_ref, fpga_ref, dac_clk, adc_clk */ /* UC, JESD, Crystal type, Lane rate, Comments */
{ 300e6, 300e6, 4800e6, 4800e6 }, /* uc0 */
};
#if !defined(AD9207_ID) && !defined(AD9209_ID)
/* TX DataPath Configuration Settings*/
/* DAC Crossbar Configuration
* Use this parameter to define Mapping from Map JRx Samples to DAC Channelizer to MAIN DAC Datapath
* For Modes that support Use Channel Interpolation > 1
* JRX Converter Samples are mapped to Channels Datapaths as follows:
* Note each AD9988_DAC_CH_X is made up of an IQ pair sample
* DUAL LINK | M | Default Channel Datapth Mapping (0-7)
* 0 | 2 | AD9988_DAC_CH_0
* 0 | 4 | AD9988_DAC_CH_0 , AD9988_DAC_CH_1
* 0 | 6 | AD9988_DAC_CH_0 , AD9988_DAC_CH_1 , AD9988_DAC_CH_2
* 0 | 8 | AD9988_DAC_CH_0 , AD9988_DAC_CH_1 , AD9988_DAC_CH_2, AD9988_DAC_CH_3
* 0 | 12 | AD9988_DAC_CH_0 , AD9988_DAC_CH_1 , AD9988_DAC_CH_2, AD9988_DAC_CH_3, AD9988_DAC_CH_4, AD9988_DAC_CH_5
* 0 | 16 | AD9988_DAC_CH_0 , AD9988_DAC_CH_1 , AD9988_DAC_CH_2, AD9988_DAC_CH_3, AD9988_DAC_CH_4, AD9988_DAC_CH_5, AD9988_DAC_CH_6, AD9988_DAC_CH_7
* 1 | 2 | Link 0: AD9988_DAC_CH_0 , Link1: AD9988_DAC_CH_4
* 1 | 4 | Link 0: AD9988_DAC_CH_0,AD9988_DAC_CH_1 , Link1: AD9988_DAC_CH_4, AD9988_DAC_CH_5
* 1 | 6 | Link 0: AD9988_DAC_CH_0,AD9988_DAC_CH_1, AD9988_DAC_CH_3 , Link1: AD9988_DAC_CH_4, AD9988_DAC_CH_5, AD9988_DAC_CH_6
* 1 | 8 | Link 0:AD9988_DAC_CH_0 , AD9988_DAC_CH_1 , AD9988_DAC_CH_2, AD9988_DAC_CH_3, Link1: AD9988_DAC_CH_4, AD9988_DAC_CH_5, AD9988_DAC_CH_6, AD9988_DAC_CH_7
* Each Main DAC Datapath may be a summation of the Channel datapaths. Use tx_dac_chan_xbar as follows to achieve that as described below.
* uint8_t tx_dac_chan_xbar[usecase][ORed List Channel (0-7) to be summed and mapped to DAC Datapath(0-3)]
* Each usecase has an Array of depth 4, each member value is the list of Channels to be mapped a Main DAC Datapath,
* where index 0 = DAC0, index 1 = DAC1 etc
* OR adi_ad9082_dac_channel_select_e enumerations to create the list
* For example: ad9988_dac_chan_xbar[0][0] =AD9988_DAC_CH_0 |AD9988_DAC_CH_1
* Map Channlizer 0 and Channelizer 1 to DAC 0
*
* For Modes that bypass Channel ie Channel Interpolation = 1 and Main DAC Interpolation > 1
* JRX Converter Samples are mapped by default to DAC Main Data apths as follows
* DUAL LINK | M | Default Main DAC Datapath Mapping (0-3) | DAC DP to DAC Mapping (0-3)
* 0 | 2 | AD9988_DAC_DP_0 | AD9988_DAC_DP_0 ->DAC 0
* 0 | 4 | AD9988_DAC_DP_0 , AD9988_DAC_DP_1 | AD9988_DAC_DP_0 ->DAC 0, AD9988_DAC_DP_1 ->DAC 1
* 0 | 6 | AD9988_DAC_DP_0 , AD9988_DAC_DP_1 , AD9988_DAC_DP_2 | AD9988_DAC_DP_0 ->DAC 0, AD9988_DAC_DP_1 ->DAC 1, AD9988_DAC_DP_2 ->DAC 2
* 0 | 8 | AD9988_DAC_DP_0 , AD9988_DAC_DP_1 , AD9988_DAC_DP_2, AD9988_DAC_DP_3 | AD9988_DAC_DP_0 ->DAC 0, AD9988_DAC_DP_1 ->DAC 1, AD9988_DAC_DP_2 ->DAC 2 , AD9988_DAC_DP_3 ->DAC 3
* 1 | 2 | Link 0: AD9988_DAC_DP_0 , Link1: AD9988_DAC_DP_2 | AD9988_DAC_DP_0 ->DAC 0, AD9988_DAC_DP_2 ->DAC 2
* 1 | 4 | Link 0: AD9988_DAC_DP_0,AD9988_DAC_DP_1 , Link1: AD9988_DAC_DP_2, AD9988_DAC_DP_3 | AD9988_DAC_DP_0 ->DAC 0, AD9988_DAC_DP_1 ->DAC 1, AD9988_DAC_DP_2 ->DAC 2 , AD9988_DAC_DP_3 ->DAC 3
* Each converter sample pair may be routed to an alternative Datapath. Use tx_dac_chan_xbar as follows to achieve that as described below.
*
* uint8_t tx_dac_chan_xbar[usecase][DAC Datapath(0-3) to be mapped to DAC (0-3)]
* Each usecase has an Array of depth 4, each member value is the DAC MAIN DP to be routed
* where index 0 = DAC0 index 1 = DAC1 etc
* For example: ad9988_dac_chan_xbar[0][1] =AD9988_DAC_DP _3
* DAC Datapath 3 is routed to DAC 1
*
*
*
*/
uint8_t tx_dac_chan_xbar[][4] = { /* dac0, dac1, dac2, dac3 */
{ AD9988_DAC_DP_0, AD9988_DAC_DP_1, AD9988_DAC_DP_2, AD9988_DAC_DP_3}, /* uc0 */
};
int64_t tx_main_shift[][4] = { /* dac0, dac1, dac2, dac3 */
{ 0, 0, 0, 0 }, /* uc0*/
};
int64_t tx_chan_shift[][8] = { /* ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7 */
{ 0, 0, 0, 0, 0, 0, 0, 0 }, /* uc0 */
};
int8_t tx_chan_gain[][8] = { /* ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7 */
{ 0, 0, 0, 0, 0, 0, 0, 0 }, /* uc0 */
};
uint8_t tx_interp[][2] = {
/* {main DUC Interpolation, Channelizer DUC Interpolation} */
{ 2, 1 }, /* uc0 */
};
#endif
/* RX Main Path DDC Enable Configuration */
/* MUX 0 & MUX 1 Settings
* List the ADC_Coarse DDCs to be mapped to logical ADCs
* OR锟絘di_ad9082_adc_coarse_ddc_select_e enumerations to create the list
* Note all DDC are enabled for all use cases that configure main datapath.
* Deselect CDDCs and FDDCs to override default Mux3 settings and enable full bandwidth mode
*/
uint8_t rx_cddc_select[] = {
AD9988_ADC_CDDC_ALL, /* uc0 */
};
/* RX Main Path DDC NCO Frequency Configuration
* List the ADC_Coarse DDCs desired Frequency Shift
* Each usecase has an Array of depth 4, each member value is the desired frequency shift (MHz)of a Coarse DDC Datapath,
* where index 0 = Frequency Shift for锟� Coarse DDC 0, index 1 = Frequency Shift for锟紺oarse DDC 1 etc
*
* For example: rx_cddc_shift[0][0] = 1842.5e6,
* For Use case 0, Frequency Shift for Coarse DDC0 is 1842.5e6MHz
*/
int64_t rx_cddc_shift[][4] = {
/* {cddc0, cddc1, cddc2, cddc3 }*/
{ 0, 0, 0, 0 }, /* uc0 */
};
/* RX Main Path DDC Data Decimation
* List the ADC_Coarse DDCs desired data decimation
* Each usecase has an Array of depth 4, each member value is the desired decimation of a Coarse DDC Datapath,
* where index 0 = Decimation Factor for锟� Coarse DDC 0, index 1 = decimation Factor for锟紺oarse DDC 1 etc
*
* For example: rx_cddc_dcm[1][0] =AD9988_CDDC_DCM_2,
* For Use case 1, Frequency Factor for Coarse DDC0 is 1
* Use adi_ad9082_adc_coarse_ddc_dcm_e to set the decimation setting
*/
uint8_t rx_cddc_dcm[][4] = {
/*{cddc0, cddc1, cddc2, cddc3} */
{ AD9988_CDDC_DCM_2, AD9988_CDDC_DCM_2, AD9988_CDDC_DCM_2, AD9988_CDDC_DCM_2 }, /* uc0 */
};
/* RX Main Path DDC Has Optional Complex to Real Convertor
* rx_cddc_c2r sets the enable for Complex to Real Converter per Main/Coarse DDC
* Each usecase has an Array of depth 4, each member value is the enable of a Coarse DDC Datapath Complex to Real Converter
* where index 0 = Enable Complex to Real Convertor for Coarse DDC 0,
* index 1 = Enable Complex to Real Convertor for Coarse DDC 1
*
* For example: rx_cddc_c2r[1][0] = 0,
* For Use case 1, Complex to Real Converter for Coarse DDC 0 is Disabled
*
*/
uint8_t rx_cddc_c2r[][4] = { /* cddc0, cddc1, cddc2, cddc3 */
{ 0, 0, 0, 0 }, /* uc0 */
};
/* RX Channelizer/Fine DDC Datapath Selection
* List the ADC Fine DDCs data path for routing Data from Main/ Coarse DDC Datapth to the JESD Tx
* Each usecase has an Array of depth 1, each member value is the masked list of Fine DDCs to be selected
* Note Coarse DDC0 & Coarse DDC1 can be routed to Fine DDC0- Fine DDC3 datapaths and
* Coarse DDC0 & Coarse DDC1 can be routed to Fine DDC4- Fine DDC6 datapaths
* For example: rx_fddc_select[3] = AD9988_ADC_FDDC_0 |AD9988_ADC_FDDC_1,
* For Use case 3, Fine DDC 0 and Fine DDC 1 are enabled
* Use adi_ad9082_adc_fine_ddc_select_e to create the list of fine DDCs to be enabled
* Note: Based on the input from the user, will apply a recommended muxing from CDDC to FDDC,
* An Error will be returned if the muxing is not supported for that devices,
* Note: If Fine DDC Decimation Factor is set to 1, Fine DDC in the Channel will be disabled
*
*/
uint8_t rx_fddc_select[] = {
AD9988_ADC_FDDC_0 | AD9988_ADC_FDDC_1 | AD9988_ADC_FDDC_2 | AD9988_ADC_FDDC_3 | AD9988_ADC_FDDC_4 | AD9988_ADC_FDDC_5 | AD9988_ADC_FDDC_6 | AD9988_ADC_FDDC_7, /* uc0 */
};
/* RX Channelizer Path DDC NCO Frequency Configuration
* List the ADC_Fine DDCs desired Frequency Shift
* Each usecase has an Array of depth 8, each member value is the desired frequency shift (MHz)of a Fine DDC Datapath,
* where index 0 = Frequency Shift for锟� Fine DDC 0, index 1 = Frequency Shift for锟紽ine DDC 1 etc
*
* For example: rx_fddc_shift[0][0] = 1842.5e6,
* For Use case 0, Frequency Shift for Fine DDC0 is 1842.5e6MHz
*/
int64_t rx_fddc_shift[][8] = {
/* fddc0, fddc1, fddc2, fddc3, fddc4, fddc5, fdddc6, fddc7 */
{ 0, 0, 0, 0, 0, 0, 0, 0 }, /* uc0 */
};
/* RX Channelizer Data Decimation
* List the ADC Fine DDCs desired data decimation
* Each usecase has an Array of depth 8, each member value is the desired decimation of a Fine DDC Datapath,
* where index 0 = Decimation factor for锟� Fine DDC 0, index 1 = decimation factor for锟紽ine DDC 1 etc
* Note where No Fine DDC Decimation is required (bypassed), Decimation factor is set to 1,AD9988_FDDC_DCM_1
*
* For example: rx_fddc_dcm[1][0] =AD9988_FDDC_DCM_4,
* For Use case 1, Decimation Factor for FineDDC0 is 4
* Use adi_ad9082_adc_fine_ddc_dcm_e to set the decimation setting
*/
uint8_t rx_fddc_dcm[][8] = { /* fddc0, fddc1, fddc2, fddc3, fddc4, fddc5, fdddc6, fddc7 */
{ AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1, AD9988_FDDC_DCM_1 }, /* uc0 */
};
uint8_t rx_fddc_c2r[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* uc */
/* Link Settings */
/* Rx Channelizer Virtual Converter Mapping
* Maps the output of a Fine DDC Data Format O/P to a JESD TX virtual converter
* Refer to Mux 4 in the Rx Digital Datapath section of the System Developer Userguide
*
* adi_ad9082_adc_fine_ddc_converter_e enerates the Fine DCC I & Q Outputs
* Each virtual converter in the JESD TX link must be assigned a source data, Fine DDC X I or Q
* Note this should be set carefully and reflect the Fine DDC selected in rx_fddc_select and also JESD TX Configuration
*
* Each usecase has an Array of depth 2, each member a list of the source of data for the virtual converter for the JESD TX Link
* where index 0 = Sources of Data for JESD TX Link 0
* where index 1 = Sources of Data for JESD TX Link 1
*
* For example: For Use Case 29 with is a Dual link JESD Mode with M =4, we specify the I & Q source for each virtual Converter
* jtx_conv_sel[28][0]={AD9988_FDDC_0_I,AD9988_FDDC_0_Q,AD9988_FDDC_1_I,AD9988_FDDC_1_Q }
* jtx_conv_sel[28][1]={AD9988_FDDC_4_I,AD9988_FDDC_4_Q,AD9988_FDDC_5_I,AD9988_FDDC_5_Q }
*/
adi_ad9988_jtx_conv_sel_t jtx_conv_sel[][2] = {
{ { AD9988_FDDC_0_I, AD9988_FDDC_0_Q },
{ AD9988_FDDC_7_I, AD9988_FDDC_7_Q }}, /* uc0 */
};
/* Total Decimation Settings */
/* The total decimation is used to calculate lane rate for each link which in
* turn is used to determine FPGA clock sources and line rates for JESD204B
*
* Each usecase has an Array of depth 2,
* where index 0 = Total decimation for link 0
* where index 1 = Total decimation for link 1
*
* For example: For Use Case 3 with is a Dual link JESD Mode, total decimation for each link
* jtx_chip_dcm[3][0]= 8
* jtx_chip_dcm[3][1]= 8
*/
uint8_t jtx_chip_dcm[][2] = {
{ 2 ,
2 }, /* uc0.link0 */
};
uint8_t jtx_logiclane_mapping_pe_brd[2][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 4, 5, 6, 7, 0, 1, 2, 3 } };
uint8_t jtx_logiclane_mapping_ce_brd[2][8] = { { 6, 4, 3, 2, 1, 0, 7, 5 }, { 2, 0, 7, 7, 7, 7, 3, 1 } };
adi_cms_jesd_param_t jrx_param[] = {
/*L F M S HD K N N' CF CS DID BID LID SC SCR Dual V Mode */
{ 4, 1, 2, 1, 1, 256, 16, 16, 0, 0, 0, 0, 0, 1, 1, 1, 2, 12 }, /* uc0 */
};
adi_cms_jesd_param_t jtx_param[][2] = {
/*L F M S HD K N N' CF CS DID BID LID SC SCR Dual V Mode C2R ModeS */
{ { 4, 1, 2, 1, 1, 256, 16, 16, 0, 0, 0, 0, 0, 1, 1, 1, 2, 13, 0, 0 },
{ 4, 1, 2, 1, 1, 256, 16, 16, 0, 0, 0, 0, 0, 1, 1, 1, 2, 13, 0, 0 } }, /* uc0 */
};
Please help me to solve this problem.
Hello, in your main program you can use adi_ad9988_dac_modulation_mux_mode_set() to use the modulator mux to split the I and Q NCO output to the separate DACs. You can also use
Thank you for replying. The function of DAC has already worked in my program, and my question is about ADCs. If you have any ideas about datapath of ADCs, please tell me more.
I find a figure of digital datapath in user guide pg45(figure 39).And I use the default configrations of these MUXs.Should I change something?And I need two ADCs for sampling high frequency complex signals, and output results being separated according to I and Q.How to choose these MUXs?
Oh oops! Sorry for misreading the question somehow.
You shouldn't need to update the adc path muxes to see the separate I and Q outputs, it just depends on the jtx_conv_sel mapping (DFOUT block).
The default the muxing setup is:
ADC0 --> adc0_x --> cddc0/2 (duplicates) --> cddc0: fddc0/2, cddc2: fddc4/6 (all the same data)
ADC1 --> adc1_x --> cddc1/3 (duplicates) --> cddc1: fddc1/3, cddc3: fddc5/7
Then jtx_conv_sel will determine which "M" (virtual converter, i.e. individual I or Q stream) takes which separated out I or Q stream.
Your current setup looks correct, you are sending fddc0_I/Q from adc0 to M0/1 of link0 and fddc7_I/Q from adc1 to M0/1 of link1. Are you capturing using the xtras app? And when you look at the L0C0, L0C1 and L1C0, L1C1 files they do not seem to correctly represent adc0 I, adc0 Q and adc1 I, adc1 Q respectively?
Thank you for answering my questions. I use vivado ila IP core to capture ADCs digital signals. When I reordered the data from JESD204C IP core,I find adc0 I and Q outputed same value,and adc1 I and Q outputed another same value.It seems adc0 and adc1 are workes independently. And I am confused about why adcs I and Q are the same.
I send a 5 MHz sine wave signal to the ADC1,and no signal to the ADC0. The result of ADC1 outputs as follows.
I export the data files,and screenshot is as follows.Obviously, data from ADC1 I are same as Q. The ADC0 outputs noise,and I and Q are the same, too.
To aviod ignoring of Q outputs durning my reordering process,I check 8 lines of gtx_rxdata from JESD204C IP core, and screemshot is as follows.Those gtx_rxdata are the whole data being transfered from AD9082.
The screenshot of data file is as follows.
It seems signals are not separated I and Q. Did I get wrong muxs setup of fddcs? I have try change fddc7_IQ to fddc5_IQ, the result are same as before. I have no idea about it. What informations should I provide you for solving my problem? Please reply to me.
Hello, I think the issue may be your setting the coarse NCO to ZIF. I understand you don't have a coarse NCO shift, but in ZIF the mixer is fully bypassed, so your real data stream from the physical adc is not getting mixed out into I and Q streams. Then you bypass the fine ddcs as well because fine interpolation = 1x, so we are also not getting the data mixed out in that section. What appears to be happening is the real data from the adc output is getting sent straight down the datapath without any DSP. Thus I think the output you are seeing is:
DFOUT_0: want FDDC0_I, getting physical ADC0 unchanged real stream
DFOUT_1: want FDDC0_Q, getting physical ADC0 real stream
DFOUT_14: want FDDC7_I, getting phy ADC1 real stream
DFOUT_15: want FDDC7_Q, getting phy ADC1 real stream
Can you try just removing the call to adi_ad9988_adc_ddc_coarse_nco_mode_set() completely?
Thank you for your suggestions.It works! Those DFOUT_x that you have listed are what I need, and I removed the program of adi_ad9988_adc_ddc_coarse_nco_mode_set(), I get both I and Q data.Thank you so much!
I found two positions using adi_ad9988_adc_ddc_coarse_nco_mode_set(),the first positions is during the adi_ad9988_device_startup_rx(), and the second positions is in the main programming and is right behind adi_ad9988_device_startup_rx().And I comment out both of them.Then the adcs outputs are separated into I and Q.
Now the configration of adc_ddc_coarse_nco_mode is Variable IF Mode. And I also want to know should I keep setting Variable IF Mode if I use a coarse NCO shift?
After solving the above problem, I send a 200 MHz sine wave signal to the ADC1 and set all cddcs shift to 180MHz.And I find outputs is mixed with two frequency. From the frequency domain, there has a -380MHz spur together with the signal of 20MHz. The frequency spectrum of ADC1 outputs is as follows.Is it corrected?
The changes of my latest programming are just two places.The one is removing adi_ad9988_adc_ddc_coarse_nco_mode_set(),and the other is setting rx_cddc_shift={180e6, 180e6, 180e6, 180e6};/*cddc0, cddc1, cddc2, cddc3 */.The rest of configurations are still default. What should I do for this problem?Looking forward to your reply, thx.
Hello, that is the expected spectrum for a complex tone. You have your 200Mhz input and its -200MHz image, then you use a 180MHz NCO shift, so your fundamental will go to 20MHz, and your image will be shifted leftward to -380MHz. Glad to hear it is working!
Another quick note here, you have set the nyquist zone to even in your app code, but your input tone is first nyquist, so you may want to remove this call. The ADC calibration is based on the nyquist zone, so you will have better performance if you set for the first zone.
Thank you! I didn't noiticed I get wrong nyquist zone.Now I change my code to set first nyquist, and the performance seems better than before.
After checking my code, I found that I made a mistake about setting NCO shift.The frequency of 180MHz was too low and it occurred spectrum aliasing. Then the -380MHz image signal had still existed which I considered as a spur. So I asked about removing those spur before, I did't notice that was the image signal. And now I notice that you have described about it, thank you so much~
Now I set a 1.2GHz NCO shift, and use first nyquist, my ADCs is functioning normally and it meets my need.Your help is very much appreciated. Hope you have a nice day!