Hello,
I am currently developing a phased array system using two LimeSDR-USB boards. For this, I need to enable one of the two boards to run off of an external clock supplied by the other board. I know it is possible to do this using the LimeSuite GUI from this discussion. Unfortunately, because I am making this for more users than just myself. I do not want the other people using the system to accidentally break something (requiring me to constantly fix it) while trying to load a config file (the normal work around) or running a command line application (like here).
It would be best if the SoapyLMS7 interface had a way to enable the external reference clock. I think I have found a quick work around for this, and I would like to see what everyone on the forum thinks.
From this discussion post and from this code from the myriadrf/LimeSuite/src/API/lms7_device.cpp github repo:
int LMS7_Device::SetClockFreq(unsigned clk_id, double freq, int channel)
{
lms_chip_id = channel == -1 ? lms_chip_id : channel/2;
lime::LMS7002M* lms = lms_list[lms_chip_id];
switch (clk_id)
{
case LMS_CLOCK_REF:
if (freq <= 0)
{
lime::ReportError(EINVAL, "Invalid frequency value.");
return -1;
}
lms->SetReferenceClk_SX(lime::LMS7002M::Tx, freq);
return 0;
case LMS_CLOCK_SXR:
if (freq <= 0)
return lms->TuneVCO(lime::LMS7002M::VCO_SXR);
if (channel != -1)
{
rx_channels[channel].cF_offset_nco = 0.0;
rx_channels[channel].freq = freq;
}
return lms->SetFrequencySX(false, freq);
case LMS_CLOCK_SXT:
if (freq <= 0)
return lms->TuneVCO(lime::LMS7002M::VCO_SXT);
if (channel != -1)
{
tx_channels[channel].cF_offset_nco = 0.0;
tx_channels[channel].freq = freq;
}
return lms->SetFrequencySX(true, freq);
case LMS_CLOCK_CGEN:
{
int ret =0;
lms->Modify_SPI_Reg_bits(LMS7param(MAC),1);
if (freq <= 0)
{
ret = lms->TuneVCO(lime::LMS7002M::VCO_CGEN);
}
else
{
ret = lms->SetInterfaceFrequency(freq, lms->Get_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP)), lms->Get_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP)));
}
if (ret != 0)
return -1;
return SetFPGAInterfaceFreq();
}
case LMS_CLOCK_RXTSP:
lime::ReportError(ENOTSUP, "Setting TSP clocks is not supported.");
return -1;
case LMS_CLOCK_TXTSP:
lime::ReportError(ENOTSUP, "Setting TSP clocks is not supported.");
return -1;
case LMS_CLOCK_EXTREF:
{
if (freq <= 0)
{
lime::info("Disabling external reference clock");
double val;
uint8_t id = 0;
connection->CustomParameterRead(&id, &val, 1, nullptr);
connection->CustomParameterWrite(&id, &val, 1, "");
return 0;
}
lime::ADF4002 module;
module.SetDefaults();
double fvco = lms->GetReferenceClk_SX(lime::LMS7002M::Rx);
int dummy;
module.SetFrefFvco(freq/1e6, fvco/1e6, dummy, dummy);
unsigned char data[12];
module.GetConfig(data);
std::vector<uint32_t> dataWr;
for(int i=0; i<12; i+=3)
dataWr.push_back((uint32_t)data[i] << 16 | (uint32_t)data[i+1] << 8 | data[i+2]);
return connection->TransactSPI(0x30, dataWr.data(), nullptr, 4);
}
default:
lime::ReportError(EINVAL, "Invalid clock ID.");
return -1;
}
}
It appears that by passing LMS_CLOCK_EXTREF into the LMS7_Device::SetClockFreq method sets up the ADF4002 module to accept an external clock of variable frequency. I am going to test this out and implement the setClockSource() Soapy API to see if this will work for what I am trying to do.
Is anyone interested in this feature being added to the official SoapyLMS7? Does someone have a better idea on how to do it?
Thanks,
Jayden Booth