# Something I learned about the CPU clock

**URL:** <https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635>\
**Category:** Freedom E300\
**Created:** [July 14, 2019, 9:44pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635 "2019-07-14T21:44:17Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![LightBulb](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/lightbulb/32/693_2.png) [@LightBulb](https://forums.sifive.com/u/LightBulb)\
**Post date:** [July 14, 2019, 9:44pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/1 "2019-07-14T21:44:17Z")

</div>

The FE310-G002 manual is not real clear about this and I discovered it by experiment. On page 30 it talks about the PLLBYPASS flag bit, which not only bypasses the PLL, it _powers it down_. The text states that the PLL can be reconfigured in this state in the PLLCFG register, which is true. It also says that the PLL should not be used until it has acheived lock.

What it does not come right out and say is that, _until_ you clear the PLLBYPASS bit, the PLL will never acheive lock because it is powered down! So the reliable sequence is,

1. **Clear** the PLLSEL bit, which makes the CPU use the Ring oscillator as the clock. For me this turns out to be 20.2 MHz with the default settings but your mileage may vary. The Ring oscillator is not very precise so don’t run this way for long.
2. Now you can **set** PLLBYPASS which powers down the PLL.
3. Change the PLL R, F, and Q factors as desired, see pages 29 and 30.
4. **Clear** PLLBYPASS. This starts up the PLL again and it will try to acheive lock.
5. Wait at least 100 microseconds for the lock indicator to become stable. I use 4 ticks of the 32 KHz low-frequency timer for this.
6. Wait for the PLLLOCKED bit to turn on. This is the high-order bit in the PLLCFG register.
7. Finally **set** the PLLSEL bit to switch the CPU from using the Ring oscillator to the PLL output.

At this point you will probably need to change the clock dividers for UARTs and SPI devices to account for the new central clock frequency.

---

<div class="post-metadata">

**Author:** ![stef](https://avatars.discourse-cdn.com/v4/letter/s/76d3ee/32.png) [@stef](https://forums.sifive.com/u/stef)\
**Post date:** [August 23, 2019, 8:07am UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/2 "2019-08-23T08:07:31Z")

</div>

Hello LightBulb,

Thank you for your post, it is very helpful.

However I am new in this field and I would like to make you a question. I have posted a question [here](http://forums.sifive.com/t/clock-generation-and-configuration/2783) about clock generation on HiFive1. I have read the documentation but it is still not clear to me how to change the values of these registers that you are mentioning. I cannot find an interface for that in the sdk, thus I assume that I should use assembly for that (or maybe I am wrong). The only relevant variables that I find in the repo are the `PLL_{R, F, Q, SEL, REFSEL, BYPASS, LOCK}` constants in [sifive\_fe310-g000\_pll.c](https://github.com/sifive/freedom-metal/blob/master/src/drivers/sifive_fe310-g000_pll.c#L16) by I am not sure if I can use these constants somehow in my code.

For example, I know that the `PLLSEL` is the 16th (numbering starts from 0) bit of the `pllcfg` register. However, I am not sure how to modify this register. Any help here is appreciated.

Thanks in advance and I am sorry if my question is silly,  
Stef

---

<div class="post-metadata">

**Author:** ![LightBulb](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/lightbulb/32/693_2.png) [@LightBulb](https://forums.sifive.com/u/LightBulb)\
**Post date:** [August 23, 2019, 1:11pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/3 "2019-08-23T13:11:30Z")

</div>

I’m sorry, I have no experience using the C libraries for the HiFive1. But looking at that code, it seems they supply high level routines to do the work for you… I would start with \_\_metal\_driver\_sifive\_fe310\_g000\_pll\_set\_rate\_hz

---

<div class="post-metadata">

**Author:** ![stef](https://avatars.discourse-cdn.com/v4/letter/s/76d3ee/32.png) [@stef](https://forums.sifive.com/u/stef)\
**Post date:** [August 23, 2019, 1:42pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/4 "2019-08-23T13:42:22Z")

</div>

> [@LightBulb](#):
>
> \_\_metal\_driver\_sifive\_fe310\_g000\_pll\_set\_rate\_hz

Hello LightBulb,

Thanks for the info. I have seen the functions that exist in this file and they seem to are for this exact purpose. However, it is not clear to me yet how I will define a valid `struct metal_clock` that I use as an argument for these functions, but I think I can figure out. Also in the meanwhile, I have examined the 16 (4\*4) bytes in the address `0x1000_8000` that contain the registers `hfrosccfg`, `hfxosccfg`, `pllcfg`, and `plloutdiv` so now I know exactly how my device is setup before I try to change anything.

I can also try modifying these registers through my code with some pointers in those addresses.

Best,  
Stef

---

<div class="post-metadata">

**Author:** ![LightBulb](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/lightbulb/32/693_2.png) [@LightBulb](https://forums.sifive.com/u/LightBulb)\
**Post date:** [August 23, 2019, 2:16pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/5 "2019-08-23T14:16:58Z")

</div>

Keep in mind that if you change the CPU clock speed, and you are using UART0 for console input or output, you must also change the UART0 clock divider to compensate, in order to maintain the same console baud rate. The J-Link interface is separate even though both come through the same USB cable.

It looks like if you call that routine with the desired clock rate, it will set a speed as close as possible to the one you request. You can’t set just any arbitrary speed, as is outlined in Chapter 6.

---

<div class="post-metadata">

**Author:** ![stef](https://avatars.discourse-cdn.com/v4/letter/s/76d3ee/32.png) [@stef](https://forums.sifive.com/u/stef)\
**Post date:** [August 23, 2019, 3:37pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/6 "2019-08-23T15:37:25Z")

</div>

> [@LightBulb](#):
>
> you must also change the UART0 clock divider to compensate

You mean that I can use the formula  
 ![uart_div](https://us1.discourse-cdn.com/flex020/uploads/sifive/original/1X/b9bc028970dc61d7a67f36453e36b52d26ee4c6c.png)

that is mentioned in the fe310 manual and set `div = cpu_frequency/fbaud - 1` right?

---

<div class="post-metadata">

**Author:** ![LightBulb](https://sea2.discourse-cdn.com/flex020/user_avatar/forums.sifive.com/lightbulb/32/693_2.png) [@LightBulb](https://forums.sifive.com/u/LightBulb)\
**Post date:** [August 24, 2019, 4:30pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/7 "2019-08-24T16:30:12Z")

</div>

yes

---

<div class="post-metadata">

**Author:** ![DanaK6JQ](https://avatars.discourse-cdn.com/v4/letter/d/5daacb/32.png) [@DanaK6JQ](https://forums.sifive.com/u/DanaK6JQ)\
**Post date:** [December 21, 2019, 11:25pm UTC](https://forums.sifive.com/t/something-i-learned-about-the-cpu-clock/2635/8 "2019-12-21T23:25:03Z")

</div>

If you’re still interested, I think this other post of mine might help

> [@How to get/set CPU clock frequency for HiFive1 Rev. B?](http://forums.sifive.com/t/how-to-get-set-cpu-clock-frequency-for-hifive1-rev-b/2335/4):
>
> @ckuehnel if you’re still looking for an example, I believe this might help - I’ll explain the testing I’ve done below slight_smile #include \<metal/machine.h\> long cpu\_clock; cpu\_clock = metal\_clock\_get\_rate\_hz(&\_\_metal\_dt\_clock\_4.clock); new\_cpu\_clock = metal\_clock\_set\_rate\_hz(&\_\_metal\_dt\_clock\_4.clock, 32000000L); The magic there is “&\_\_metal\_dt\_clock\_4.clock”, have a look at bsp/install/include/metal/machine/inline.h for others I’m pretty-sure this is correct, I tried it on a Spa…

Cheers,  
Dana
