ttrftech / NanoVNA

Very Tiny Palmtop Vector Network Analyzer
1.06k stars 296 forks source link

Work around si5351 #122

Closed DiSlord closed 4 years ago

DiSlord commented 4 years ago

Tru undestand how config I2C bus

static const I2CConfig i2ccfg = {
  0x00300506, //voodoo magic 400kHz @ HSI 8MHz
  0,
  0
};

Refer manual for I2C_TIMINGR register not get this value for 400kHz @ HSI 8MHz

If get example values from manual for 500kHz @ HSI 8MHz and change STM32_TIMINGR_SCLL from 6 to 5-3, possible get 7% sweep speed

static const I2CConfig i2ccfg = {
  // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235))
  // 500kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
  STM32_TIMINGR_PRESC(0U)  |
  STM32_TIMINGR_SCLDEL(1U) | STM32_TIMINGR_SDADEL(0U) |
  STM32_TIMINGR_SCLH(3U)   | STM32_TIMINGR_SCLL(5U),
  // 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
//  STM32_TIMINGR_PRESC(0U)  |
//  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) |
//  STM32_TIMINGR_SCLH(3U)   | STM32_TIMINGR_SCLL(9U),
  // Old values voodoo magic 400kHz @ HSI 8MHz ???
//  STM32_TIMINGR_PRESC(0U)  |
//  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(0U) |
//  STM32_TIMINGR_SCLH(5U)   | STM32_TIMINGR_SCLL(6U),
  0,          // CR1 register initialization.
  0           // CR2 register initialization.
};

Try test it

DiSlord commented 4 years ago

Also if change I2C bus clock to 48MHz, #define STM32_I2C1SW STM32_I2C1SW_SYSCLK And set 400kHz timing settings, allow get less noise (good see on 900-1500MHz)

400kHz @ 48MHz I2C clock from refrence manual get best result (sweep speed increased, and less noise on freq 900-1500MHz)

  STM32_TIMINGR_PRESC(5U)  |
  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) |
  STM32_TIMINGR_SCLH(3U)   | STM32_TIMINGR_SCLL(9U),
DiSlord commented 4 years ago

Also now allow set #define DELAY_CHANNEL_CHANGE 2 and get good measure result

DiSlord commented 4 years ago

At last, best result give this settings: I2C HSI = 8MHz #define STM32_I2C1SW STM32_I2C1SW_HSI

i2ccfg
// I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h
// STM32_I2C1SW = STM32_I2C1SW_HSI     (HSI=8MHz)
// STM32_I2C1SW = STM32_I2C1SW_SYSCLK  (SYSCLK = 48MHz)
static const I2CConfig i2ccfg = {
  // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235))
  // 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
//  STM32_TIMINGR_PRESC(5U)  |
//  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) |
//  STM32_TIMINGR_SCLH(3U)   | STM32_TIMINGR_SCLL(9U),
// 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
  STM32_TIMINGR_PRESC(0U)  |
  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) |
  STM32_TIMINGR_SCLH(3U)   | STM32_TIMINGR_SCLL(9U),
// Old values voodoo magic 400kHz @ HSI 8MHz
//  STM32_TIMINGR_PRESC(0U)  |
//  STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(0U) |
//  STM32_TIMINGR_SCLH(5U)   | STM32_TIMINGR_SCLL(6U),
  0,          // CR1 register initialization.
  0           // CR2 register initialization.
};

#define DELAY_GAIN_CHANGE 2 #define DELAY_CHANNEL_CHANGE 2

si5351.c

#define DELAY_NORMAL 2
#define DELAY_BANDCHANGE 0
#define DELAY_LOWBAND 2

Try check it

DiSlord commented 4 years ago

Additional

    // div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1
    si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
    si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
    si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 6, CLK2_FREQUENCY,
                                  SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1);

Every freq for band 1 and 2 update send Chanel 0 settings (SI5351_PLL_A), Chanel 1 settings (SI5351_PLL_B and freq Multisynth), and here broke CH2 clock freq (processor, audio codec clock) Chanel 2 settings (SI5351_PLL_B), restore correct Multisynth and CH2 clock freq

As minimum need need send CH2 settings before, as maximum at some time apply all or not use it

Possibly this hack used for fix it on band 1?

    // Set PLL twice on changing from band 2
    if (current_band == 2) {
      si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
      si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
    }
DiSlord commented 4 years ago

I2C bus speed not define freq stability, it just define data transfer speed to si5351

Found some problems in si5351.c it contain a lot of hack, need undestand how better solve it At test i get up to 2x speed. Need just minimise I2C data transfer and do correct control

Pmax65 commented 4 years ago

HI DiSlord,

Possibly this hack used for fix it on band 1?

// Set PLL twice on changing from band 2
if (current_band == 2) {
  si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
  si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
}

As far I know, that has been thought to avoids PLL unlocks at frequencies around 300MHz.

About the MCLK "arrhythmia": I'm working to an HW mod to improve the odd harmonics behavior when the DUT is an high order low-pass filter that lets pass frequencies in the fundamental carrier range stopping the frequencies in its harmonics range and I discovered that the "arrhythmia" is due to the function si5351_disable_output() used into function si5351_set_frequency_with_offset(...). In fact, function si5351_disable_output() suspends CLK2 output every times the band changes and re-enables it only until si5351_enable_output() is called at the end of si5351_set_frequency_with_offset(...).

In my HW mod (which I ended yesterday and I'll publish soon), I added an external 8MHz oscillator for the MCLK and used CLK2 to get an harmonics only reference signal that fixes the odd harmonics issue. The mod, in few words, uses CLK1 output to source the DUT below 300MHz, while it uses CLK2 output to source the DUT above 300MHz passing the reference signal through a 5th order high-pass elliptic filter (in this case the Si5351A is used as an RF switch, both its outputs generate the very same frequency, but one at time).

Have a great day.

Massimo IK1IZA

DiSlord commented 4 years ago

Found why need this hack

// Set PLL twice on changing from band 2
if (current_band == 2) {
  si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul);
  si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul);
}

si5153 have some delay on change MultiSynth Integer and non Integer Mode. Need send MultiSynth and CLK Control twice on change from fractional divider mode

PS Not need enable/disable output on band change. I get good result:

#define DELAY_NORMAL 2
#define DELAY_BANDCHANGE 1
//#define DELAY_LOWBAND 0

/*
 * configure output as follows:
 * CLK0: frequency + offset
 * CLK1: frequency
 * CLK2: fixed 8MHz
 */

int
si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength)
{
  uint8_t band;
  int delay = DELAY_NORMAL;
  if (freq == lastfreq)
      return delay;
  uint32_t ofreq = freq + offset;
  uint32_t mul = 1, omul = 1;
  uint32_t rdiv = SI5351_R_DIV_1;
  lastfreq = freq;
  if (freq >= FREQ_HARMONICS * 7U) {
    mul = 9;
    omul = 11;
  } else if (freq >= FREQ_HARMONICS * 5U) {
    mul = 7;
    omul = 9;
  } else if (freq >= FREQ_HARMONICS * 3U) {
    mul = 5;
    omul = 7;
  } else if (freq >= FREQ_HARMONICS) {
    mul = 3;
    omul = 5;
  }
  else if (freq <= 500000U) {
    rdiv = SI5351_R_DIV_64;
    freq *= 64;
    ofreq *= 64;
  } else if (freq <= 4000000U) {
    rdiv = SI5351_R_DIV_8;
    freq *= 8;
    ofreq *= 8;
  }

  if ((freq / mul) < 100000000U) {
    band = 1;
  } else if ((freq / mul) < 150000000U) {
    band = 2;
  } else {
    band = 3;
  }
  switch (band) {
  case 1:
    // fractional divider mode.
    if (current_band != 1){
      si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1);
//      si5351_setupPLL(SI5351_REG_PLL_B, PLL_N, 0, 1);
      si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_A, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
    }
    si5351_set_frequency_fixedpll(0, SI5351_REG_PLL_A, XTALFREQ * PLL_N * omul, ofreq, rdiv, drive_strength);
    si5351_set_frequency_fixedpll(1, SI5351_REG_PLL_A, XTALFREQ * PLL_N *  mul,  freq, rdiv, drive_strength);
//    delay += DELAY_LOWBAND;
    break;
  case 2:
    // div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1
    si5351_set_frequency_fixeddiv(0, SI5351_REG_PLL_A, ofreq, 6, drive_strength, omul);
    si5351_set_frequency_fixeddiv(1, SI5351_REG_PLL_B,  freq, 6, drive_strength,  mul);
    si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B,  freq / mul * 6, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
    // Send MultiSynth and CLK Control twice on change from fractional divider mode
    if (current_band == 1){
      si5351_set_frequency_fixeddiv(0, SI5351_REG_PLL_A, ofreq, 6, drive_strength, omul);
      si5351_set_frequency_fixeddiv(1, SI5351_REG_PLL_B,  freq, 6, drive_strength,  mul);
    }
    break;
  case 3:
    // div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1
    si5351_set_frequency_fixeddiv(0, SI5351_REG_PLL_A, ofreq, 4, drive_strength, omul);
    si5351_set_frequency_fixeddiv(1, SI5351_REG_PLL_B,  freq, 4, drive_strength,  mul);
    si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B,  freq / mul * 4, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
    // Send MultiSynth and CLK Control twice on change from fractional divider mode
    if (current_band == 1){
        si5351_set_frequency_fixeddiv(0, SI5351_REG_PLL_A, ofreq, 4, drive_strength, omul);
        si5351_set_frequency_fixeddiv(1, SI5351_REG_PLL_B,  freq, 4, drive_strength,  mul);
    }
    break;
  }

  if (current_band != band) {
    si5351_reset_pll();
    current_band = band;
    delay += DELAY_BANDCHANGE;
  }
  return delay;
}

I also fix some integer overflow on calculation

DiSlord commented 4 years ago

Seems i solve all hack for si5351, soon i add Pull request

Sweep freq speedup from 8400 sys tick to 5300 (about 40% speedup) Need just test stability

Commit fixes to https://github.com/DiSlord/NanoVNA

DiSlord commented 4 years ago

Create pull request