/***************************************************************************//** * @brief Checks if the DCO is locked * * @return Returns 1 if the DCO is locked, 0 otherwise. *******************************************************************************/ int32_t ad9643_is_dco_locked() { int32_t ret = -1, cnt; uint32_t stat; ad9643_testmode_set(0x2, AD9643_TEST_MODE_PN23_SEQ); ad9643_testmode_set(0x1, AD9643_TEST_MODE_PN9_SEQ); ADC_Core_Write(ADC_CORE_PN_ERR_CTRL, ADC_CORE_PN23_1_EN | ADC_CORE_PN9_0_EN); ad9643_read(AD9643_REG_DCO_OUTPUT_DELAY); ADC_Core_Write(ADC_CORE_ADC_STAT, ADC_CORE_ADC_STAT_MASK); delay_us(1000); ADC_Core_Read(ADC_CORE_ADC_STAT, &stat); if(!( stat & 0x3c)) { ret = 0; } ad9643_testmode_set(0x3, AD9643_TEST_MODE_OFF); return ret < 0 ? 0 : 1; }
/**************************************************************************//** * @brief Calibrates the ADC DCO clock delay * * @return If success, returns DCO clock delay code. If the DCO clock is * inverted 0x100 is added to the returned DCO value * if error,return -1 ******************************************************************************/ int32_t XCOMM_CalibrateAdcDco(void) { int32_t ret; ADC_Core_Write(ADC_CORE_DMA_CHAN_SEL,0x00); ad9643_dco_clock_invert(0); ret = ad9643_dco_calibrate_2c(); ADC_Core_Write(ADC_CORE_DMA_CHAN_SEL,0x02); return ret; }
/***************************************************************************//** * @brief Sets the AD9643 test mode for DCO delay calibration * * @param chan_mask - Selects the internal ADC the command is applied to. * @param mode - ADC test mode * * @return Negative error code or 0 in case of success. *******************************************************************************/ int32_t ad9643_testmode_set(uint32_t chan_mask, uint32_t mode) { int32_t ret = 0; switch (mode) { case AD9643_TEST_MODE_PN23_SEQ: case AD9643_TEST_MODE_PN9_SEQ: case AD9643_TEST_MODE_ALTERNATING_CHECKERBOARD: ADC_Core_Write(ADC_CORE_ADC_CTRL,0); ret = ad9643_write(AD9643_REG_OUTPUT_MODE, (AD9643_OUTPUT_MODE_DEF | AD9643_OUTPUT_MODE_TWOS_COMPLEMENT) & ~AD9643_OUTPUT_MODE_TWOS_COMPLEMENT); break; default: ADC_Core_Write(ADC_CORE_ADC_CTRL,ADC_CORE_SIGNEXTEND); ret = ad9643_write(AD9643_REG_OUTPUT_MODE, (AD9643_OUTPUT_MODE_DEF | AD9643_OUTPUT_MODE_TWOS_COMPLEMENT)); }; if(ret < 0) return ret; ret = ad9643_write(AD9643_REG_CHANNEL_IDX, chan_mask); if(ret < 0) return ret; ret = ad9643_write(AD9643_REG_TEST_MODE, mode); if(ret < 0) return ret; ret = ad9643_write(AD9643_REG_CHANNEL_IDX, AD9643_CHANNEL_IDX_ADC_AB); if(ret < 0) return ret; ret = ad9643_write(AD9643_REG_TRANSFER, AD9643_TRANSFER_EN); if(ret < 0) return ret; return ret; }
/***************************************************************************//** * @brief Initializes the AD9643. * * @return Negative error code or 0 in case of success. *******************************************************************************/ int32_t ad9643_setup() { int32_t ret = 0; ad9643_reset(); ad9643_write(AD9643_REG_CLK_PHASE_CTRL, AD9643_CLK_PHASE_CTRL_EVEN_ODD_MODE_EN); ADC_Core_Write(ADC_CORE_ADC_CTRL,ADC_CORE_SIGNEXTEND | ADC_CORE_SCALE_OFFSET_EN); ADC_Core_Write(ADC_CORE_CA_OFFS_SCALE,ADC_CORE_OFFSET(0) | ADC_CORE_SCALE(0x8000)); ADC_Core_Write(ADC_CORE_CB_OFFS_SCALE,ADC_CORE_OFFSET(0) | ADC_CORE_SCALE(0x8000)); ad9643_write(AD9643_REG_OUTPUT_MODE, AD9643_OUTPUT_MODE_DEF | AD9643_OUTPUT_MODE_TWOS_COMPLEMENT); ad9643_write(AD9643_REG_TEST_MODE, AD9643_TEST_MODE_OFF); ad9643_write(AD9643_REG_TRANSFER, AD9643_TRANSFER_EN); ret = ad9643_dco_calibrate_2c(); if(ret < 0) { ad9643_dco_clock_invert(1); ret = ad9643_dco_calibrate_2c(); } ADC_Core_Write(ADC_CORE_DMA_CHAN_SEL,0x02); return ret < 0 ? -1 : 0; }
/**************************************************************************//** * @brief Calibrates the ADC DCO clock delay * * @return If success, returns DCO clock delay code * if error,return -1 ******************************************************************************/ int32_t XCOMM_CalibrateAdcDco(void) { int32_t ret; ADC_Core_Write(ADC_CORE_DMA_CHAN_SEL,0x00); ad9643_dco_clock_invert(0); ret = ad9643_dco_calibrate_2c(); if(ret<0) { ad9643_dco_clock_invert(1); ret = ad9643_dco_calibrate_2c(); if (!(ret<0)) { ret |= 0x0100; } } ADC_Core_Write(ADC_CORE_DMA_CHAN_SEL,0x02); return ret; }
/***************************************************************************//** * @brief Calibrates the DCO clock delay * * @return Negative error code or DCO clock delay code in case of success. *******************************************************************************/ int32_t ad9643_dco_calibrate_2c() { int32_t dco, ret, cnt, start, max_start, max_cnt; uint32_t stat; uint32_t regVal; uint8_t err_field[33]; ad9643_testmode_set(0x2, AD9643_TEST_MODE_PN23_SEQ); ad9643_testmode_set(0x1, AD9643_TEST_MODE_PN9_SEQ); ADC_Core_Write(ADC_CORE_PN_ERR_CTRL, ADC_CORE_PN23_1_EN | ADC_CORE_PN9_0_EN); for(dco = 0; dco <= 32; dco++) { ret = -1; ad9643_write(AD9643_REG_DCO_OUTPUT_DELAY, dco > 0 ? ((dco - 1) | 0x80) : 0); ad9643_write(AD9643_REG_TRANSFER, AD9643_TRANSFER_EN); ad9643_read(AD9643_REG_DCO_OUTPUT_DELAY); ADC_Core_Write(ADC_CORE_ADC_STAT, ADC_CORE_ADC_STAT_MASK); delay_us(1000); ADC_Core_Read(ADC_CORE_ADC_STAT, &stat); if(!( stat & 0x3c)) { ret = 0; } err_field[dco] = !!ret; } ret = -1; for(dco = 0, cnt = 0, max_cnt = 0, start = -1, max_start = 0; dco <= 32; dco++) { if (err_field[dco] == 0) { if (start == -1) start = dco; cnt++; ret = 0; } else { if (cnt > max_cnt) { max_cnt = cnt; max_start = start; } start = -1; cnt = 0; } } if (cnt > max_cnt) { max_cnt = cnt; max_start = start; } dco = max_start + (max_cnt / 2); regVal = dco > 0 ? ((dco - 1) | 0x80) : 0; ad9643_testmode_set(0x3, AD9643_TEST_MODE_OFF); ad9643_write(AD9643_REG_DCO_OUTPUT_DELAY,regVal); ad9643_write(AD9643_REG_TRANSFER, AD9643_TRANSFER_EN); return ret < 0 ? -1 : (regVal & 0x1F); }