What if you use the “safe” boot loader mode? You should be able to reprogram it then. You do it by double tapping the reset button (when it flashes green, hit the reset button again, it should blink red indicating it’s in safe bootloader mode).
By the way @dvc, I believe the problem with your code snippet above is that in your CoreClock block you aren’t ensuring that you are running off HFROSC before changing the PLL settings. I don’t know what you did before this, but make sure that you are running off the HFROSC before changing anything about the PLL (including switching it to use the HFXOSC bypass). The HFROSC is designed to allow you to change its settings while running off of it, the PLL is not.
Note that on the HiFive1, there is no LFXOSC. The LFROSC is also not used, because there is a pin which selects the LFCLK source to be the external 32kHz MEMS Oscillator on the board. This is not controllable by software. It’s still worth turning off the LFROSC since the board isn’t using it.
mmh, doesn’t the bypass field control the mux in FIgure 4.1: E300 clock generation scheme (psdclkbypass_n)? In the diagram that looks like it’s outside the PLL block.
HFXOSC: bypass 0
HFROSC: pllsel 0, bypass 1
Ok I misunderstood the diagram, now it makes sense…
I find all this very confusing and it doesn’t seem to be easy to find a clear definition of the various oscillators and clocks.
Could you please correct anything erroneous in the following?
there is a Low Frequency Oscillator LFROSC on the FE310, which can be used as the source of a LFCLK that the CPU can run from. I don’t know what frequency the on-chip LFOSC can run at.
however on the HiFive1 the LFCLK is selected to come from an external clock, which is 32 kHz.
there is a High Frequency Oscillator, which uses an external 16 MHz crystal.
there is a PLL which runs at some integer multiple of the HFOSC, with 16 and 20 being the most common (256 and 320 MHz)
@brucehoult Maybe my clock driver helps clarify things. It’s intended to be bullet proof not efficient (but most of the functions are inlined so it’s pretty good actually).
impl<'a> CoreClock<'a> {
pub unsafe fn use_external(&self, clint: &Clint) {
self.use_pll(clint, |_, w| {
// bypass PLL
w.bypass().bit(true)
// select HFXOSC
.refsel().bit(true)
}, |w| w.divby1().bit(true));
}
unsafe fn wait_for_lock(&self, clint: &Clint) {
// Won't lock when bypassed and will loop forever
if !self.0.pllcfg.read().bypass().bit_is_set() {
// Wait for PLL Lock
// Note that the Lock signal can be glitchy.
// Need to wait 100 us
// RTC is running at 32kHz.
// So wait 4 ticks of RTC.
let time = clint.get_mtime() + ::aonclk::Ticks(4);
while clint.get_mtime() < time {}
// Now it is safe to check for PLL Lock
while !self.0.pllcfg.read().lock().bit_is_set() {}
}
}
pub unsafe fn use_pll<F, G>(&self, clint: &Clint, pllcfg: F, plloutdiv: G)
where
for<'w> F: FnOnce(&prci::pllcfg::R,
&'w mut prci::pllcfg::W) -> &'w mut prci::pllcfg::W,
for<'w> G: FnOnce(&'w mut prci::plloutdiv::W) -> &'w mut prci::plloutdiv::W,
{
// Make sure we are running of internal clock
// before configuring the PLL.
self.use_internal();
// Enable HFXOSC
self.0.hfxosccfg.write(|w| w.enable().bit(true));
// Wait for HFXOSC to stabilize
while !self.0.hfxosccfg.read().ready().bit_is_set() {}
// Configure PLL
self.0.pllcfg.modify(pllcfg);
self.0.plloutdiv.write(plloutdiv);
// Wait for PLL lock
self.wait_for_lock(clint);
// Switch to PLL
self.0.pllcfg.modify(|_, w| {
w.sel().bit(true)
});
// Disable HFROSC to save power
self.0.hfrosccfg.write(|w| w.enable().bit(false));
}
pub unsafe fn use_internal(&self) {
// Enable HFROSC
self.0.hfrosccfg.write(|w| {
w.enable().bit(true)
// It is OK to change this even if we are running off of it.
// Reset them to default values.
.div().bits(4)
.trim().bits(16)
});
// Wait for HFROSC to stabilize
while !self.0.hfrosccfg.read().ready().bit_is_set() {}
// Switch to HFROSC
self.0.pllcfg.modify(|_, w| {
w.sel().bit(false)
});
// Bypass PLL to save power
self.0.pllcfg.modify(|_, w| {
w.bypass().bit(true)
// Select HFROSC as PLL ref to disable HFXOSC later
.refsel().bit(false)
});
// Disable HFXOSC to save power.
self.0.hfxosccfg.write(|w| w.enable().bit(false));
}
}
I’ve read the C code sources for the system. And just like there, this code is simply using names such as “hfosc” (and all the others) without defining or describing them in any adequate way.
At manufacturing time configuration options:
psdclkbypass_n (pulled up on G000) so HFXOSC is always used through the PLL regardless of if it’s bypassed or not.
psdlfclksel (pulled down on G000) so LFROSC can’t be used and psdlfaltclk is always used.
@brucehoult from your list of 4, all is correct, except that for point (4), the reason we are able to achieve the higher PLL frequency is by using the HFROSC (as apposed to the HFXOSC) as the source to the PLL, then increasing its frequency (by tweaking its trim settings) until we reach the 320 MHz.
@dvc there is no LFXOSC in the FE310-G000, only LFROSC and external clock pin lfaltclk (in other words, it does not have low-frequency crystal driver pads).
The point is well taken from this conversation that the exact clock configuration in the FE310-G000 Silicon + 48-pin package + HiFive1 board all need to be more clear, vs the generic FE300 clocking scheme.
Some other things that are unclear to me:
Where are the sources for the OTP code?
Is there any documentation on the SBI other than the code in the linux port? Are any sbi calls implemented in the OTP? Obviously 6 and 7 aren’t, but RTOS’s might benefit from the other ones…
Ah, I didn’t read the getting started guide. The additional notes section is the missing piece I was looking for. Maybe you can put that with the schematic which is something I’m more likely to read