Skip to content

Commit

Permalink
add IQ mode 90 deg phase shift and suppoty fo 2 si5351
Browse files Browse the repository at this point in the history
  • Loading branch information
paulh002 committed May 24, 2023
1 parent d6c2dda commit 842f7a6
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 31 deletions.
18 changes: 13 additions & 5 deletions SoapyHifiBerry.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "AudioInput.h"
#include "AudioOutput.h"
#include "si5351.h"
#include "TCA9548.h"
#include "configfile.h"

/*-------------------------------------------------------
Expand All @@ -34,6 +35,10 @@
#define CLK_VFO_TX SI5351_CLK1
#define CLK_NA SI5351_CLK2

#define CLK_VFO_I SI5351_CLK0
#define CLK_VFO_Q SI5351_CLK1


const int hifiBerry_BufferSize = 2048;

typedef enum hifiberrysdrStreamFormat
Expand Down Expand Up @@ -167,16 +172,19 @@ class SoapyHifiBerry : public SoapySDR::Device
bool i2c_available;
std::vector<sdr_stream *> streams;

unique_ptr<HifiBerryAudioOutputput> uptr_HifiBerryAudioOutputput;
unique_ptr<HifiBerryAudioInput> uptr_HifiBerryAudioInput;
unique_ptr<cfg::File> uptr_cfg;
std::unique_ptr<HifiBerryAudioOutputput> uptr_HifiBerryAudioOutputput;
std::unique_ptr<HifiBerryAudioInput> uptr_HifiBerryAudioInput;
std::unique_ptr<cfg::File> uptr_cfg;

SoapyHifiBerryDataBuffer<IQSample> source_buffer_rx;
SoapyHifiBerryDataBuffer<IQSample> source_buffer_tx;
unique_ptr<Si5351> pSI5351;
std::unique_ptr<Si5351> pSI5351;
std::unique_ptr<Si5351> pSI5351tx;
std::unique_ptr<TCA9548> pTCA9548;

int get_int(string section, string key);
string get_string(string section, string key);
std::string get_string(string section, string key);
si5351_drive txDrive, rxDrive;
SoapySDR::Range rxGain{-12, 40};
bool modeIQ;
};
105 changes: 82 additions & 23 deletions SoapyHifiBerrySettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
* Device interface
**********************************************************************/
const cfg::File::ConfigMap defaultOptions = {
{"si5351", {{"correction", cfg::makeOption("0")}, {"rxdrive", cfg::makeOption("2")}, {"t.xdrive", cfg::makeOption("2")}}},
{"sound", {{"device", cfg::makeOption("snd_rpi_hifiberry_dacplusadcpro")}, {"samplerate", cfg::makeOption("192000")}, {"input", cfg::makeOption("DIFF")}}}
};
{"si5351", {{"correction", cfg::makeOption("0")}, {"mode", cfg::makeOption("single")} , {"rxdrive", cfg::makeOption("2")}, {"t.xdrive", cfg::makeOption("2")}}},
{"sound", {{"device", cfg::makeOption("snd_rpi_hifiberry_dacplusadcpro")}, {"samplerate", cfg::makeOption("192000")}, {"input", cfg::makeOption("DIFF")}}}};

int SoapyHifiBerry::get_int(string section, string key)
{
Expand Down Expand Up @@ -41,6 +40,7 @@ SoapyHifiBerry::SoapyHifiBerry(const SoapySDR::Kwargs &args)
SoapySDR_log(SOAPY_SDR_INFO, "SoapyHifiBerry::SoapyHifiBerry constructor called");
no_channels = 1;
txDrive = rxDrive = SI5351_DRIVE_2MA;
modeIQ = false;

uptr_cfg = make_unique<cfg::File>();
if (!uptr_cfg->loadFromFile("hifiberry.cfg"))
Expand Down Expand Up @@ -120,22 +120,59 @@ SoapyHifiBerry::SoapyHifiBerry(const SoapySDR::Kwargs &args)
//numid = 25, iface = MIXER, name = 'ADC Mic Bias'
uptr_HifiBerryAudioOutputput->controle_alsa(25, 0);

pSI5351 = make_unique<Si5351>("/dev/i2c-1",SI5351_BUS_BASE_ADDR);
if (pSI5351->init(SI5351_CRYSTAL_LOAD_8PF, 0, 0))
std::string IQMode = SoapyHifiBerry::get_string("si5351", "mode");
if (IQMode != "IQ")
{
cout << "si5351 found" << endl;
pSI5351->set_correction((long)corr, SI5351_PLL_INPUT_XO);
pSI5351->drive_strength(CLK_VFO_RX, rxDrive);
pSI5351->drive_strength(CLK_VFO_TX, txDrive);
pSI5351->output_enable(CLK_VFO_RX, 1);
pSI5351->output_enable(CLK_VFO_TX, 0);
pSI5351->output_enable(CLK_NA, 0);
pSI5351->update_status();
pSI5351 = make_unique<Si5351>("/dev/i2c-1", SI5351_BUS_BASE_ADDR);
if (pSI5351->init(SI5351_CRYSTAL_LOAD_8PF, 0, 0))
{
cout << "si5351 found" << endl;
pSI5351->set_correction((long)corr, SI5351_PLL_INPUT_XO);
pSI5351->drive_strength(CLK_VFO_RX, rxDrive);
pSI5351->drive_strength(CLK_VFO_TX, txDrive);
pSI5351->output_enable(CLK_VFO_RX, 1);
pSI5351->output_enable(CLK_VFO_TX, 0);
pSI5351->output_enable(CLK_NA, 0);
pSI5351->update_status();
}
else
{
cout << "No si5351 found" << endl;
pSI5351.reset(nullptr);
}
}
else
{
cout << "No si5351 found" << endl;
pSI5351.reset(nullptr);
pTCA9548 = std::make_unique<TCA9548>("/dev/i2c-1", 0x70);
pTCA9548->begin(1);
pSI5351 = make_unique<Si5351>("/dev/i2c-1", SI5351_BUS_BASE_ADDR);
if (pSI5351->init(SI5351_CRYSTAL_LOAD_8PF, 0, 0))
{
pSI5351->drive_strength(CLK_VFO_I, rxDrive);
pSI5351->drive_strength(CLK_VFO_Q, rxDrive);
pSI5351->output_enable(CLK_VFO_I, 1);
pSI5351->output_enable(CLK_VFO_Q, 0);
pSI5351->output_enable(CLK_NA, 0);
pSI5351->update_status();
}
pTCA9548->setChannelMask(2);
pSI5351tx = make_unique<Si5351>("/dev/i2c-1", SI5351_BUS_BASE_ADDR);
if (pSI5351tx->init(SI5351_CRYSTAL_LOAD_8PF, 0, 0))
{
pSI5351tx->drive_strength(CLK_VFO_I, rxDrive);
pSI5351tx->drive_strength(CLK_VFO_Q, rxDrive);
pSI5351tx->output_enable(CLK_VFO_I, 1);
pSI5351tx->output_enable(CLK_VFO_Q, 0);
pSI5351tx->output_enable(CLK_NA, 0);
pSI5351tx->update_status();
}
if (pSI5351 == nullptr || pSI5351tx == nullptr)
{
cout << "No si5351 found" << endl;
pSI5351.reset(nullptr);
pSI5351tx.reset(nullptr);
}
modeIQ = true;
}
}

Expand Down Expand Up @@ -317,19 +354,41 @@ void SoapyHifiBerry::setFrequency(const int direction, const size_t channel, con
if (direction == SOAPY_SDR_RX)
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyHifiBerry::setFrequency called RX");

uint64_t freq = (uint64_t)frequency * SI5351_FREQ_MULT * 4;
if (pSI5351)
pSI5351->set_freq(freq, CLK_VFO_RX);

if (modeIQ)
{
if (pSI5351)
{
pTCA9548->setChannelMask(1);
pSI5351->setIQFrequency((long)frequency);
}
}
else
{
uint64_t freq = (uint64_t)frequency * SI5351_FREQ_MULT * 4;
if (pSI5351)
pSI5351->set_freq(freq, CLK_VFO_RX);
}
}

if (direction == SOAPY_SDR_TX)
{
SoapySDR_log(SOAPY_SDR_INFO, "SoapyHifiBerry::setFrequency called TX");

uint64_t freq = (uint64_t)frequency * SI5351_FREQ_MULT * 4;
if (pSI5351)
pSI5351->set_freq(freq, CLK_VFO_TX);

if (modeIQ)
{
if (pSI5351tx)
{
pTCA9548->setChannelMask(2);
pSI5351tx->setIQFrequency((long)frequency);
}
}
else
{
uint64_t freq = (uint64_t)frequency * SI5351_FREQ_MULT * 4;
if (pSI5351)
pSI5351->set_freq(freq, CLK_VFO_RX);
}
}

}
Expand Down
50 changes: 48 additions & 2 deletions si5351.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ extern "C" {
/* Public functions */
/********************/

Si5351::Si5351(const char *i2c_device_filepath, uint8_t i2c_addr)
: i2c_bus_addr(i2c_addr), i2c_file(0), i2c_filepath(i2c_device_filepath)
Si5351::Si5351(const char *i2c_device_filepath, uint8_t i2c_addr, si5351_clock i_clock, si5351_clock q_clock)
: i2c_bus_addr(i2c_addr), i2c_file(0), i2c_filepath(i2c_device_filepath), iclock(i_clock), qclock(q_clock)


{
Expand All @@ -52,6 +52,7 @@ Si5351::Si5351(const char *i2c_device_filepath, uint8_t i2c_addr)
pllb_ref_osc = SI5351_PLL_INPUT_XO;
clkin_div = SI5351_CLKIN_DIV_1;
i2c_file = 0;
lastMult = -1;
}

Si5351::~Si5351()
Expand Down Expand Up @@ -1827,3 +1828,48 @@ uint8_t Si5351::select_r_div_ms67(uint64_t *freq)

return r_div;
}

void Si5351::setIQFrequency(long freq)
{
int mult = 0;

if (freq < 5000000)
mult = 150;
else if (freq < 6000000)
mult = 120;
else if (freq < 8000000)
mult = 100;
else if (freq < 11000000)
mult = 80;
else if (freq < 15000000)
mult = 50;
else if (freq < 22000000)
mult = 40;
else if (freq < 30000000)
mult = 30;
else if (freq < 40000000)
mult = 20;
else if (freq < 50000000)
mult = 15;
else if (freq < 90000000)
mult = 10;

uint64_t f = freq * 100ULL;
uint64_t pllFreq = freq * mult * 100ULL;

int32_t correction = get_correction(SI5351_PLL_INPUT_XO);
pllFreq = pllFreq + (int32_t)((((((int64_t)correction) << 31) / 1000000000LL) * pllFreq) >> 31);
printf("pll = %ld Mhz \n", pllFreq);

set_freq_manual(f, pllFreq, iclock);
set_freq_manual(f, pllFreq, qclock);

if (mult != lastMult)
{
set_phase(iclock, 0);
set_phase(qclock, mult);
pll_reset(SI5351_PLLA);
update_status();
lastMult = mult;
}
}
5 changes: 4 additions & 1 deletion si5351.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,13 @@ struct Si5351IntStatus
class Si5351
{
public:
Si5351(const char *i2c_device_filepath, uint8_t i2c_addr = SI5351_BUS_BASE_ADDR);
Si5351(const char *i2c_device_filepath, uint8_t i2c_addr = SI5351_BUS_BASE_ADDR, si5351_clock iclock = SI5351_CLK0, si5351_clock qclock = SI5351_CLK1);
~Si5351();
bool init(uint8_t, uint32_t, int32_t);
void reset(void);
uint8_t set_freq(uint64_t, enum si5351_clock);
uint8_t set_freq_manual(uint64_t, uint64_t, enum si5351_clock);
void setIQFrequency(long freq);
void set_pll(uint64_t, enum si5351_pll);
void set_ms(enum si5351_clock, struct Si5351RegSet, uint8_t, uint8_t, uint8_t);
void output_enable(enum si5351_clock, uint8_t);
Expand Down Expand Up @@ -371,6 +372,8 @@ class Si5351

int i2c_file;
std::string i2c_filepath;
int lastMult;
si5351_clock iclock, qclock;
};

#endif /* SI5351_H_ */

0 comments on commit 842f7a6

Please sign in to comment.