//
// Copyright 2010-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include "x300_adc_ctrl.hpp"
#include "ads62p48_regs.hpp"
#include
#include
#include
#include
using namespace uhd;
x300_adc_ctrl::~x300_adc_ctrl(void){
/* NOP */
}
/*!
* A X300 codec control specific to the ads62p48 ic.
*/
class x300_adc_ctrl_impl : public x300_adc_ctrl
{
public:
x300_adc_ctrl_impl(uhd::spi_iface::sptr iface, const size_t slaveno):
_iface(iface), _slaveno(slaveno)
{
init();
}
void init()
{
//power-up adc
_ads62p48_regs.reset = 1;
this->send_ads62p48_reg(0x00); //issue a reset to the ADC
_ads62p48_regs.reset = 0;
_ads62p48_regs.enable_low_speed_mode = 0;
_ads62p48_regs.ref = ads62p48_regs_t::REF_INTERNAL;
_ads62p48_regs.standby = ads62p48_regs_t::STANDBY_NORMAL;
_ads62p48_regs.power_down = ads62p48_regs_t::POWER_DOWN_NORMAL;
_ads62p48_regs.lvds_cmos = ads62p48_regs_t::LVDS_CMOS_DDR_LVDS;
_ads62p48_regs.channel_control = ads62p48_regs_t::CHANNEL_CONTROL_INDEPENDENT;
_ads62p48_regs.data_format = ads62p48_regs_t::DATA_FORMAT_2S_COMPLIMENT;
_ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_MINUS4_26;
_ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_MINUS4_26;
this->send_ads62p48_reg(0);
this->send_ads62p48_reg(0x20);
this->send_ads62p48_reg(0x3f);
this->send_ads62p48_reg(0x40);
this->send_ads62p48_reg(0x41);
this->send_ads62p48_reg(0x44);
this->send_ads62p48_reg(0x50);
this->send_ads62p48_reg(0x51);
this->send_ads62p48_reg(0x52);
this->send_ads62p48_reg(0x53);
this->send_ads62p48_reg(0x55);
this->send_ads62p48_reg(0x57);
this->send_ads62p48_reg(0x62);
this->send_ads62p48_reg(0x63);
this->send_ads62p48_reg(0x66);
this->send_ads62p48_reg(0x68);
this->send_ads62p48_reg(0x6a);
this->send_ads62p48_reg(0x75);
this->send_ads62p48_reg(0x76);
}
void reset()
{
init();
}
double set_gain(const double &gain)
{
const meta_range_t gain_range = meta_range_t(0, 6.0, 0.5);
const int gain_bits = int((gain_range.clip(gain)*2.0) + 0.5);
_ads62p48_regs.gain_chA = gain_bits;
_ads62p48_regs.gain_chB = gain_bits;
this->send_ads62p48_reg(0x55);
this->send_ads62p48_reg(0x68);
return gain_bits/2;
}
void set_test_word(const std::string &patterna, const std::string &patternb, const uint32_t num)
{
_ads62p48_regs.custom_pattern_low = num & 0xff;
_ads62p48_regs.custom_pattern_high = num >> 8;
if (patterna == "ones") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_ONES;
if (patterna == "zeros") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_ZEROS;
if (patterna == "custom") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_CUSTOM;
if (patterna == "ramp") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_RAMP;
if (patterna == "normal") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_NORMAL;
if (patternb == "ones") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_ONES;
if (patternb == "zeros") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_ZEROS;
if (patternb == "custom") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_CUSTOM;
if (patterna == "ramp") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_RAMP;
if (patterna == "normal") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_NORMAL;
this->send_ads62p48_reg(0x51);
this->send_ads62p48_reg(0x52);
this->send_ads62p48_reg(0x62);
this->send_ads62p48_reg(0x75);
}
~x300_adc_ctrl_impl(void)
{
_ads62p48_regs.power_down = ads62p48_regs_t::POWER_DOWN_GLOBAL;
UHD_SAFE_CALL
(
this->send_ads62p48_reg(0x40);
)
}
private:
ads62p48_regs_t _ads62p48_regs;
uhd::spi_iface::sptr _iface;
const size_t _slaveno;
void send_ads62p48_reg(uint8_t addr)
{
uint16_t reg = _ads62p48_regs.get_write_reg(addr);
_iface->write_spi(_slaveno, spi_config_t::EDGE_FALL, reg, 16);
}
};
/***********************************************************************
* Public make function for the ADC control
**********************************************************************/
x300_adc_ctrl::sptr x300_adc_ctrl::make(uhd::spi_iface::sptr iface, const size_t slaveno)
{
return sptr(new x300_adc_ctrl_impl(iface, slaveno));
}