Skip to content
Scott James Remnant edited this page Dec 26, 2016 · 4 revisions

Several of the peripherals inside the Raspberry Pi rely on clocks to provide accurate timing, or frequencies. Certain GPIO pins have a clock as an alternate function, and hardware such as the PWM, PCM, and DMA Engine use clocks as a timing source.

Clocks allow us to generate consistent and accurate timing information, at a rate we determine. Programming a clock simply consists of setting the timing that we want, and starting or stopping the clock appropriately.

Registers

Documentation for the clocks is covered in p105–108, and this gives the register locations for the General Purpose clocks that can be output to GPIO pins. Unfortunately this doesn't give us the registers for the PCM or PWM clocks, for those we have to read the errata, or the separate BCM2835 Audio Clocks supplement.

Clock CTL Register Address DIV Register Address
GP0 0x7e101070 0x7e101074
GP1* 0x7e101078 0x7e10107c
GP2 0x7e101080 0x7e101084
PCM 0x7e101098 0x7e10109c
PWM 0x7e1010a0 0x7e1010a4

* Note: GP1 is possibly used for the Ethernet port, so not usable.

Each clock has two registers, one Control register, and one Divisor register. These are both 32-bit words consecutively in memory.

let peripheralBlockSize = 0x1000
let clockRegistersOffset = 0x101000

guard let clockRegisters = mmap(nil, peripheralBlockSize, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, off_t(peripheralAddressBase + clockRegistersOffset)),
      clockRegisters != MAP_FAILED else { fatalError("Couldn't mmap clock registers") }
      
let gp0CtlOffset = 0x70
let gp0DivOffset = 0x74

let gp0Ctl = clockRegisters.advanced(by: gp0CtlOffset).bindMemory(to: Int.self, capacity: 1)
let gp0Div = clockRegisters.advanced(by: gp0DivOffset).bindMemory(to: Int.self, capacity: 1)

Clock Sources

The first thing we need to consider when programming a clock is the underlying timing source. There's little useful documentation on this, but the user community has discovered the frequencies of these by experiment:

Clock Source Frequency
0, 8–15 Ground 0 Hz
1 Oscillator 19.2 Mhz
2 testdebug0 0 Hz
3 testdebug1 0 Hz
4 PLLA 0 Hz
5 PLLC* 1,000 MHz
6 PLLD 500 Mhz
7 HDMI auxiliary 216 Mhz

* PLLC changes with overclock settings.

Ultimately this gives us two useful clock sources whose values we can rely on: the 19.2 Mhz oscillator, and the 500 Mhz PLLD (Phase-Locked Loop is a type of clock source).

As we'll see, the relatively wide spread of these will come in useful.

Integer Divisor

The two clock sources give us two possible frequencies: 19.2 Mhz, and 500 Mhz; but we'll usually need something lower than this. We can't simply adjust the clock frequency, because other hardware might be using the same source for its timing, so we use another technique: skipping signals.

For example if we use the 500 Mhz PLLD source, but skip every other signal, the resulting frequency is 250 Mhz. If we skip every third, it's 166.67 Mhz; and every fourth it's 125 Mhz, and so on.

The number of signals we skip thus acts as an integer divisor, and is how we configure the individual clocks, based on the same sources, to be at different output frequencies.

To configure the integer divisor (DIVI), 12 bits of the Divisor register are used. Obviously division by zero is not mathematically possible, and a divisor of one corresponds to no divisor at all. The maximum divisor value is the largest we can fit in the bits: 4,095.

This means that there's a different lower bound of frequency we can obtain, depending on our selection of clock source. With PLLD the lowest output frequency we can obtain is 122 Khz, while with the oscillator it's a fraction under 4.7 Khz.

Thus where we need a lower output frequency, the oscillator will be the correct choice of source; while PLLD is the correct choice for a higher output frequency.

Fractional Divisor and MASH

We can't always get the exact values we want with just the integer divisor though.

For example if we wanted a clock of 2 Mhz, there are two ways to obtain it: we can use PLLD and an integer divisor of 250, giving us a resulting clock of exactly 2 Mhz; or we can use the oscillator and an integer divisor of 9, which gives us the close-but-not-quite rate of 2.13 Mhz.

Obviously we would pick PLLD as the source, but for some values we don't have a choice.

Say instead we needed a clock of 220 Mhz, this is above the range possible with the oscillator, but there's no integer divisor that would work for PLLD either—the closest, 2, is 30 Mhz too high!

As noted, we can't change the clock source frequency, and simply dropping a fixed number of input signals doesn't work since that's what the integer divisor is already doing.

But what we can do is drop a variable number of input signals; for example if the desired target output frequency is halfway between two possible integer divisors, we can use the lower one, then the higher one, and repeat that pattern.

When the target output frequency is closer to one possible integer divisor than the other, we simply repeat that one more than the higher one.

Each individual frequency will be either too high or too low, but the average over time will match our intended output frequency. By introducing noise-shaping as well, we can eliminate some of the perceived non-random jitter; especially important for applications where a human might be able to discern the effect of the skipping.

For many purposes, the combination of variable skipping, and noise-shaping, will be good enough.

The ratio of too-high to too-low skips is configured by the 12-bit Fractional part of the Divisor register (DIVF) while the MASH noise-shaping is configured with the appropriate bits in the Control register.

Note that it's not possible to use a Fractional Divisor with out at least one level of noise-shaping. When the MASH setting is set to zero, only the Integer Divisor is used.

Configuring the Output Frequency

First, and most importantly, the documentation is wrong! The fractional divisor has a range of 1–4,095, and the fractional result is equivalent to dividing that value by 4,096. A fractional divisor value of 2,048 is equivalent to 0.5, not a value of 512 as the documentation suggests.

To obtain the right value we can use the following:

(SourceFrequency ÷ OutputFrequency - IntegerDivisor) × 4096

For our example target of 220 Mhz, where we already know that the Integer Divisor value will be 2:

500 ÷ 220 = 2.272727

2.272727 - 2 = 0.272727

0.272727 × 4096 = 1117

So our fractional divisor will be 1,117. This literally means that out of 4,096 individual input clock signals, 1,117 will use an integer divisor of the next highest value (3, thus 166.67 Mhz), while the remainder will use the integer divisor configured (2, thus 250 Mhz).

This will give us a resulting average output frequency within 2 Khz of 220 Mhz; likely close enough for our needs.

Here is a corrected table from the datasheet:

MASH Min DIVI Min Output Freq Avg Output Freq Max Output Freq
0 1 source ÷ DIVI source ÷ DIVI source ÷ DIVI
1 2 source ÷ (DIVI + 1) source ÷ (DIVI + DIVF ÷ 4096) source ÷ (DIVI)
2 3 source ÷ (DIVI + 2) source ÷ (DIVI + DIVF ÷ 4096) source ÷ (DIVI - 1)
3 5 source ÷ (DIVI + 4) source ÷ (DIVI + DIVF ÷ 4096) source ÷ (DIVI - 3)

Note that higher MASH noise-shaping levels also increase the minimum value of the Integer Divisor. In this case, since we need to use 2 as the integer divisor, only 1-level MASH is available to us which gives us a low amount of noise-shaping. Good for an internal timing source, bad for the human ear.

As you can see, it's important to select the appropriate clock source, integer divisor, MASH setting, and if necessary fractional divisor to achieve not just the desired frequency, but based on the intended use of the signal as well.

Setting the Clock

Both the Control and Divisor registers are used to configure the clock, and both require a "password" when writing otherwise the write will be ignored. This password is the number 0x5a in the most-significant byte of the word.

First we need to stop any existing running clock, we do this by writing to the Control register with a zero bit in the Enable position. We can then wait for the clock's Busy status to clear.

gp0Ctl.pointee = 0x5a000000 | (gp0Ctl.pointee & ~(1 << 4))
while gp0Ctl.pointee & (1 << 7) != 0 { }

Note that we're careful to only remove the Enable bit, and not set other registers to zero. Many of the other bits cannot be changed while the Busy status is set, and if we did so by simply writing 0, we could jam the clock. If that happens we can kill it by writing the Kill bit 1 << 5.

Also note that we can't simply use &= either, because each write to the clock register has to have the value 5a in the most-significant byte as a "password", and this isn't returned by reading the register.

With the clock no longer running, we are free to set the registers up. We can't do this at the same time we enable the clock though, so we set the source, MASH, integer, and fractional divisors up first.

let src = 6 // PLLD
let mash = 1
let divi = 2
let divf = 1117

gp0Ctl.pointee = 0x5a000000 | (mash << 9) | (src << 0)
gp0Div.pointee = 0x5a000000 | (divi << 12) | (divf << 0)

Again note the password, and that it's required for the divisor register as well.

Now we can enable the clock; for safety it's worth adding a small delay here for the above values to be read by the hardware before changing the register again. We use the platform library usleep function for this.

usleep(100)

gp0Ctl.pointee = 0x5a000000 | (gp0Ctl.pointee | (1 << 4))
while gp0Ctl.pointee & (1 << 7) == 0 { }

Also note again that we're careful to just change the enable flag and not alter the others. Once the clock's Busy status bit is set, we know that it's running.

That's all there is to it, now the clock can be used from whatever secondary hardware requires the timing signal.