How to switch to 16 MHz external oscillator?

Hello, I am trying to switch to HFXOSC with the following code:

volatile uint32_t * pll_reg = (volatile uint32_t *) PRCI_PLLCFG;
volatile uint32_t * high_freq_reg = (volatile uint32_t *) PRCI_HFROSCCFG;
volatile uint32_t * spi0 = (volatile uint32_t *) 0x10014000;

#ifdef USE_HFROSC
  /* Setting up osc frequency */
  uint32_t tmp_reg = 0;
  /* Install divider in high frequency oscillator */
  tmp_reg |= (HFROSC_DIV_VAL & 0x2f) << HFROSC_DIV_OFFSET;
  tmp_reg |= (HFROSC_TRIM_VAL & 0x1F) << HFROSC_TRIM_OFFSET;
  tmp_reg |= (HFROSC_EN_VAL & 0x1) << HFROSC_EN_OFFSET;
  (*high_freq_reg) = tmp_reg;
  while (( (*high_freq_reg) & ((HFROSC_RDY_VAL & 0x1) \
                  << HFROSC_RDY_OFFSET)) == 0 ) {
    ;
  }
#endif /* USE_HFROSC */

#ifdef USE_HFXOSC
  volatile uint32_t * ext_freq_reg = (volatile uint32_t *) PRCI_HFXOSCCFG;
  (*ext_freq_reg) |= ((HFXOSC_EN_VAL & 0x1) << HFXOSC_EN_OFFSET);
  while (( (*ext_freq_reg) & ((HFXOSC_RDY_VAL & 0x1) \
                  << HFXOSC_RDY_OFFSET)) == 0 ) {
    ;
  }
  (*spi0) = 8;
  (*high_freq_reg) &= ~(0x1 << HFROSC_EN_OFFSET);

#endif /* USE_HFXOSC */
#ifndef USE_PLL
  /* Disable PLL */
  (*pll_reg) &= ~(0x1 << PLL_SEL_OFFSET);
#else

#endif

But when I am trying to turn off HFROSC, openOCDs starts to output:
Info : dtmcontrol_idle=5, dbus_busy_delay=3, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=4, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=5, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=6, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=7, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=8, interrupt_high_delay=226
Info : dtmcontrol_idle=5, dbus_busy_delay=9, interrupt_high_delay=226

At the same time, I can change the frequency of HFROSC. As you can see, I have also tried to change an spi0 divider value.
What can be the reason of such behavior?

Sounds like you are turning off the clock while you’re still running off of it. You need to make sure you are actually running off the other clock source before you turn off the HFROSC.

Suggest taking a took at Figure 4.1 in the FE300 Platform Manual (https://www.sifive.com/documentation/freedom-soc/freedom-e300-platform-reference-manual/) to understand exactly what that means.

You can also see example functions for what you’re trying to do in the Freedom E SDK’s PRCI driver: https://github.com/sifive/freedom-e-sdk/blob/master/bsp/drivers/fe300prci/fe300prci_driver.c

Also, note that the HFROSC is specifically designed to allow you to change its frequency while you’re running off of it. The PLL is not, so any time you want to change PLL settings, you must first turn on the HFROSC and run off of it.

Thank you, it seems that pll should be enable in order to run off of HFXOSC. Now it works.