Skip to content

Commit

Permalink
soapy: Fix AD9361 error message
Browse files Browse the repository at this point in the history
soapy: Tune AD9361 to ISM band on startup
soapy: Set AD9361 TX attenuation higher on startup
soapy: Set AD9361 gain mode to manual on startup
soapy: Round I2S clock dividers
soapy: Round SPI clock dividers
soapy: Add TX flush logic to RF Timestamping module
soapy: Add methods to wait for TX/RX/Counter enable/disable
soapy: Work on CLI tool
soapy: Add methods to round SI5351 frequency to nearest valid value
soapy: Gate streaming trace messages at compile time with macros, to reduce overhead
soapy: Implement KWArgs parsing on device instantiation
soapy: Implement TX streaming
soapy: Misc changes

Signed-off-by: João Silva <jgc3silva@gmail.com>
  • Loading branch information
vankxr committed Apr 6, 2024
1 parent ced04c7 commit 84ec1dc
Show file tree
Hide file tree
Showing 15 changed files with 3,146 additions and 724 deletions.
17 changes: 6 additions & 11 deletions software/soapy/src/AD9361.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,11 +679,6 @@ void AD9361::writeReg(uint16_t reg, uint8_t *src, uint8_t count)
if(count > 8)
throw std::invalid_argument("AD9361: Max SPI size exceeded");

// SoapySDR_logf(SOAPY_SDR_DEBUG, "AD9361: Writing %d bytes to register 0x%03X", count, reg);

// for(uint8_t i = 0; i < count; i++)
// SoapySDR_logf(SOAPY_SDR_DEBUG, "AD9361: 0x%02X", src[i] & 0xFF);

uint16_t cmd = BIT(15); // Write command
cmd |= (count - 1) << 12; // Number of bytes to read
cmd |= reg; // Register address
Expand Down Expand Up @@ -738,7 +733,7 @@ AD9361::AD9361(AD9361::SPIConfig spi, AD9361::GPIOConfig reset_gpio, AD9361::GPI
uint8_t pid = this->readReg(AD9361_REG_PRODUCT_ID);

if((pid & PRODUCT_ID_MASK) != PRODUCT_ID_9361)
throw std::runtime_error("AD9361: Product ID mismatch (" + std::to_string(pid) + " != " + std::to_string(PRODUCT_ID_9361) + ")");
throw std::runtime_error("AD9361: Product ID mismatch (" + std::to_string(pid & PRODUCT_ID_MASK) + " != " + std::to_string(PRODUCT_ID_9361) + ")");
}
AD9361::~AD9361()
{
Expand Down Expand Up @@ -795,8 +790,8 @@ void AD9361::init()
this->pdata->ensm_pin_ctrl = false;

/* LO Control */
this->pdata->rx_synth_freq = 98000000UL; // TODO: Auto
this->pdata->tx_synth_freq = 100000000UL; // TODO: Auto
this->pdata->rx_synth_freq = 433000000ULL; // TODO: Auto
this->pdata->tx_synth_freq = 433000000ULL; // TODO: Auto
this->pdata->lo_powerdown_managed_en = true;

/* Rate & BW Control */
Expand All @@ -822,7 +817,7 @@ void AD9361::init()
this->pdata->rf_tx_output_sel = 0;

/* TX Attenuation Control */
this->pdata->tx_atten = 10000;
this->pdata->tx_atten = 80000;
this->pdata->update_tx_gain_via_alert = false;

/* Reference Clock Control */
Expand All @@ -840,8 +835,8 @@ void AD9361::init()
this->pdata->clkout_mode = AD9361::ClkOutMode::DISABLE;

/* Gain Control */
this->pdata->gain_ctrl.rx1_mode = AD9361::RFGainCtrlMode::RF_GAIN_SLOWATTACK_AGC;
this->pdata->gain_ctrl.rx2_mode = AD9361::RFGainCtrlMode::RF_GAIN_SLOWATTACK_AGC;
this->pdata->gain_ctrl.rx1_mode = AD9361::RFGainCtrlMode::RF_GAIN_MGC;
this->pdata->gain_ctrl.rx2_mode = AD9361::RFGainCtrlMode::RF_GAIN_MGC;
this->pdata->gain_ctrl.adc_large_overload_thresh = 58;
this->pdata->gain_ctrl.adc_ovr_sample_size = 4;
this->pdata->gain_ctrl.adc_small_overload_thresh = 47;
Expand Down
18 changes: 18 additions & 0 deletions software/soapy/src/AXII2S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ void AXII2S::setMCLKClockFrequency(uint64_t input_freq, uint64_t mclk_freq)
{
uint64_t mclk_div = input_freq / mclk_freq;

if(mclk_div & 1)
mclk_div++; // Round up to nearest even number

this->setMCLKClockDivider(mclk_div);
}
uint64_t AXII2S::getMCLKClockFrequency(uint64_t input_freq)
Expand Down Expand Up @@ -80,6 +83,9 @@ void AXII2S::setBCLKClockFrequency(uint64_t input_freq, uint64_t bclk_freq)
{
uint64_t bclk_div = input_freq / bclk_freq;

if(bclk_div & 1)
bclk_div++; // Round up to nearest even number

this->setBCLKClockDivider(bclk_div);
}
uint64_t AXII2S::getBCLKClockFrequency(uint64_t input_freq)
Expand Down Expand Up @@ -111,6 +117,9 @@ void AXII2S::setLRCLKClockFrequency(uint64_t input_freq, uint64_t lrclk_freq)
{
uint64_t lrclk_div = input_freq / lrclk_freq;

if(lrclk_div & 1)
lrclk_div++; // Round up to nearest even number

this->setLRCLKClockDivider(lrclk_div);
}
uint64_t AXII2S::getLRCLKClockFrequency(uint64_t input_freq)
Expand Down Expand Up @@ -152,6 +161,15 @@ void AXII2S::setClockFrequencies(uint64_t input_freq, uint64_t mclk_freq, uint64
uint64_t bclk_div = input_freq / bclk_freq;
uint64_t lrclk_div = input_freq / lrclk_freq;

if(mclk_div & 1)
mclk_div++; // Round up to nearest even number

if(bclk_div & 1)
bclk_div++; // Round up to nearest even number

if(lrclk_div & 1)
lrclk_div++; // Round up to nearest even number

this->setClockDividers(mclk_div, bclk_div, lrclk_div);
}
uint64_t AXII2S::setClockFrequencies(uint64_t input_freq, uint64_t mclk_freq, uint64_t samp_rate)
Expand Down
223 changes: 219 additions & 4 deletions software/soapy/src/AXIRFTStamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,61 @@ void AXIRFTStamp::triggerClockResync(bool wait, uint32_t timeout_ms)
}
}

void AXIRFTStamp::flushTX(uint32_t timeout_ms)
{
std::unique_lock<std::recursive_mutex> lock(this->mutex);

if(this->isTXEnabled())
throw std::runtime_error("AXI RF Timestamping: Cannot flush TX while at least one TX is enabled");

if(this->isTXCounterEnabled())
throw std::runtime_error("AXI RF Timestamping: Cannot flush TX while at least one TX counter is enabled");

this->writeReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT_ALL, AXI_RF_TSTAMP_REG_CH_CTL_STAT_TX_FLUSH_EN);

uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

lock.unlock();
while(--timeout && (this->isTXDMAReady(AXIRFTStamp::Channel::CH0) || this->isTXDMAReady(AXIRFTStamp::Channel::CH1)))
usleep(10);
lock.lock();

this->writeReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT_ALL, AXI_RF_TSTAMP_REG_CH_CTL_STAT_TX_FLUSH_DIS);

if(this->isTXDMAReady(AXIRFTStamp::Channel::CH0))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX0 flush");

if(this->isTXDMAReady(AXIRFTStamp::Channel::CH1))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX1 flush");
}
void AXIRFTStamp::flushTX(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
if(ch >= AXIRFTStamp::Channel::CH_MAX)
throw std::invalid_argument("AXI RF Timestamping: Invalid channel number: " + std::to_string(ch) + " (Max = " + std::to_string(AXIRFTStamp::Channel::CH_MAX) + ")");

std::unique_lock<std::recursive_mutex> lock(this->mutex);

if(this->isTXEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Cannot flush TX while TX is enabled");

if(this->isTXCounterEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Cannot flush TX while TX counter is enabled");

this->writeReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch), AXI_RF_TSTAMP_REG_CH_CTL_STAT_TX_FLUSH_EN);

uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

lock.unlock();
while(--timeout && this->isTXDMAReady(ch))
usleep(10);
lock.lock();

this->writeReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch), AXI_RF_TSTAMP_REG_CH_CTL_STAT_TX_FLUSH_DIS);

if(this->isTXDMAReady(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX flush");
}

void AXIRFTStamp::enableTX(bool enable)
{
std::lock_guard<std::recursive_mutex> lock(this->mutex);
Expand Down Expand Up @@ -151,6 +206,46 @@ bool AXIRFTStamp::isTXEnabled(AXIRFTStamp::Channel ch)

return !!(this->readReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch)) & AXI_RF_TSTAMP_REG_CH_CTL_STAT_TX_STAT);
}
void AXIRFTStamp::waitTXEnabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isTXEnabled())
usleep(10);

if(!this->isTXEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX enable");
}
void AXIRFTStamp::waitTXEnabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isTXEnabled(ch))
usleep(10);

if(!this->isTXEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " enable");
}
void AXIRFTStamp::waitTXDisabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isTXEnabled())
usleep(10);

if(this->isTXEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX disable");
}
void AXIRFTStamp::waitTXDisabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isTXEnabled(ch))
usleep(10);

if(this->isTXEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " disable");
}
void AXIRFTStamp::enableRX(bool enable)
{
std::lock_guard<std::recursive_mutex> lock(this->mutex);
Expand Down Expand Up @@ -183,6 +278,46 @@ bool AXIRFTStamp::isRXEnabled(AXIRFTStamp::Channel ch)

return !!(this->readReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch)) & AXI_RF_TSTAMP_REG_CH_CTL_STAT_RX_STAT);
}
void AXIRFTStamp::waitRXEnabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isRXEnabled())
usleep(10);

if(!this->isRXEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX enable");
}
void AXIRFTStamp::waitRXEnabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isRXEnabled(ch))
usleep(10);

if(!this->isRXEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " enable");
}
void AXIRFTStamp::waitRXDisabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isRXEnabled())
usleep(10);

if(this->isRXEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX disable");
}
void AXIRFTStamp::waitRXDisabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isRXEnabled(ch))
usleep(10);

if(this->isRXEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " disable");
}

void AXIRFTStamp::enableCounter(bool enable)
{
Expand Down Expand Up @@ -215,6 +350,46 @@ bool AXIRFTStamp::isTXCounterEnabled(AXIRFTStamp::Channel ch)

return !!(this->readReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch)) & AXI_RF_TSTAMP_REG_CH_CTL_STAT_CNT_TX_STAT);
}
void AXIRFTStamp::waitTXCounterEnabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isTXCounterEnabled())
usleep(10);

if(!this->isTXCounterEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX counter enable");
}
void AXIRFTStamp::waitTXCounterEnabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isTXCounterEnabled(ch))
usleep(10);

if(!this->isTXCounterEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " counter enable");
}
void AXIRFTStamp::waitTXCounterDisabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isTXCounterEnabled())
usleep(10);

if(this->isTXCounterEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX counter disable");
}
void AXIRFTStamp::waitTXCounterDisabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isTXCounterEnabled(ch))
usleep(10);

if(this->isTXCounterEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " counter disable");
}
void AXIRFTStamp::enableRXCounter(bool enable)
{
this->writeReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT_ALL, enable ? AXI_RF_TSTAMP_REG_CH_CTL_STAT_CNT_RX_EN : AXI_RF_TSTAMP_REG_CH_CTL_STAT_CNT_RX_DIS);
Expand All @@ -237,6 +412,46 @@ bool AXIRFTStamp::isRXCounterEnabled(AXIRFTStamp::Channel ch)

return !!(this->readReg(AXI_RF_TSTAMP_REG_CH_CTL_STAT(ch)) & AXI_RF_TSTAMP_REG_CH_CTL_STAT_CNT_RX_STAT);
}
void AXIRFTStamp::waitRXCounterEnabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isRXCounterEnabled())
usleep(10);

if(!this->isRXCounterEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX counter enable");
}
void AXIRFTStamp::waitRXCounterEnabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && !this->isRXCounterEnabled(ch))
usleep(10);

if(!this->isRXCounterEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " counter enable");
}
void AXIRFTStamp::waitRXCounterDisabled(uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isRXCounterEnabled())
usleep(10);

if(this->isRXCounterEnabled())
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX counter disable");
}
void AXIRFTStamp::waitRXCounterDisabled(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
uint64_t timeout = (uint64_t)timeout_ms * 100ULL;

while(--timeout && this->isRXCounterEnabled(ch))
usleep(10);

if(this->isRXCounterEnabled(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " counter disable");
}

void AXIRFTStamp::armCounterLatch(bool req_arm)
{
Expand Down Expand Up @@ -375,7 +590,7 @@ void AXIRFTStamp::waitTXDMAReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
usleep(10);

if(!this->isTXDMAReady(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX DMA ready");
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " DMA ready");
}
void AXIRFTStamp::waitRXDMAReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
Expand All @@ -385,7 +600,7 @@ void AXIRFTStamp::waitRXDMAReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
usleep(10);

if(!this->isRXDMAReady(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX DMA ready");
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " DMA ready");
}
void AXIRFTStamp::waitTXDataReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
Expand All @@ -395,7 +610,7 @@ void AXIRFTStamp::waitTXDataReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
usleep(10);

if(!this->isTXDataReady(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX data ready");
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for TX" + std::to_string(ch) + " data ready");
}
void AXIRFTStamp::waitRXDataReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
{
Expand All @@ -405,7 +620,7 @@ void AXIRFTStamp::waitRXDataReady(AXIRFTStamp::Channel ch, uint32_t timeout_ms)
usleep(10);

if(!this->isRXDataReady(ch))
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX data ready");
throw std::runtime_error("AXI RF Timestamping: Timed out waiting for RX" + std::to_string(ch) + " data ready");
}

bool AXIRFTStamp::wasTXDMAReady(AXIRFTStamp::Channel ch)
Expand Down
3 changes: 3 additions & 0 deletions software/soapy/src/AXISPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ void AXISPI::setClockFrequency(uint64_t input_freq, uint64_t sck_freq)
{
uint64_t sck_div = input_freq / sck_freq;

if(sck_div & 1)
sck_div++; // Round up to nearest even number

this->setClockDivider(sck_div);
}
uint64_t AXISPI::getClockFrequency(uint64_t input_freq)
Expand Down
Loading

0 comments on commit 84ec1dc

Please sign in to comment.