blippy
Posts: 123
Joined: Fri Nov 03, 2017 3:07 pm

Why is the free running counter set to 3E?

Tue Dec 01, 2020 11:14 am

On p197 of the BCM2835 datasheet it describes the TCR (timer control register). Bits 23:16 of base+0x40C are set to 0x3E by default, which is for the free running counter pre-scaler. It states that

freq = sys_clk/(prescaler+1).

Firstly, what is the value of sys_clk? I've seen 250MHz quotes in one place, and 1MHz in another.

Secondly, what is the rationale of using the value 0x3E (decimal 62)? If I assume that sys_clk = 1Mhz, then this implies freq = 1e6/(62+1) = 15873Hz. Why such an odd choice, and of what use is this frequency anyway? It seems a bit low and arbitrary to do anything useful.

Thirdly, bits 3:2 of the TCR sets the pre-scale bits, being either 1, 16 or 256 for "pre-scale is clock". But wait, I thought bits 23:16 set the pre-scaler. so what does all this mean?

Fourthly, is the system_clock_freq mentioned on p11 of the datasheet the same as sys_clk mentioned above?

Fifthly, what is meant by the term "system clock" anyway? Am I right in thinking that it's the rate at which the CPU operates? So some chips will run at 1GHz, for example. And this is in contradistinction from a system "tick", which is a counter that increments based on the system clock frequency and a prescaler?

It can be quite cryptic reading datasheets sometimes, and sorting out concepts in my head. Sometimes it seems that the more I know, the less I understand.

blippy
Posts: 123
Joined: Fri Nov 03, 2017 3:07 pm

Re: Why is the free running counter set to 3E?

Tue Dec 01, 2020 1:09 pm

Just a little update to add more confusion ...

The documentation makes reference to the "standard SP804 time control register", which apparently doesn't exist anyway. I'm not sure what the 804 is supposed to be anyway. But anyhoo ...

At base+0x41C, the default value is 0x7D (p198). This is the "pre_divider". It goes on to say:
timer_clock = apb_clock/(pre_divider+1)
I'm not sure how the apb_clock relates to the "system" clock, but I think that the apb_clock runs at 250MHz. So if you set the divisor to 0xF9 ( (decimal 249), then you obtain a timer clock frequency of 1MHz (=250MHz/(249+1)).

The reset value appear to be 0x7D (decimal 125) according to the datasheet, giving a timer_clock frequency of ~1.98MHz (=250MHz/(125+1)).

Again, this seems illogical, as why not set it to 0x7C so that the timer_clock works out at exactly 2MHz?

As an experiment, I set the divisor to 0xF9 so that the timer_clock is at 1MHz (or so I think, anyway). If I set the timer counter load values (base+0x400) and reload values (base+0x418) to 799 (=2*400-1) then, according to my oscilloscope, I get a frequency of 400Hz by doing pin toggling using an interrupt. My "oscilloscope" is a really cheapo Chinese job that cost me £29, and I think it's accuracy is a little dubious. But it seems to be spot-on.

Ah, OK. I think I'm getting mixed up (hardly difficult). There are actually two timers starting at 0x7E00B400: a free-running one, and one where you can set the reload value. They can run at completely different frequencies (is this true?). Bits 23:16 and 3:2 at base+0x40C are related to the free-running one, and (presumably) don't affect the resetable one.

I don't know why there seems to be two mentions of the prescaler in those bits. Maybe you have to multiply them together?? And I still haven't figured out what the sys_clk frequency is.

Comments?

I expect by this stage no-one has the foggiest idea what I'm talking about or what my point is.

trejan
Posts: 3064
Joined: Tue Jul 02, 2019 2:28 pm

Re: Why is the free running counter set to 3E?

Tue Dec 01, 2020 1:55 pm

blippy wrote:
Tue Dec 01, 2020 1:09 pm
The documentation makes reference to the "standard SP804 time control register", which apparently doesn't exist anyway. I'm not sure what the 804 is supposed to be anyway. But anyhoo ...
Arm Ltd sells peripheral IP cores. The PL011 UARTs in the Pi SoC is one of them. SP804 is https://developer.arm.com/documentation/ddi0271/d/

blippy
Posts: 123
Joined: Fri Nov 03, 2017 3:07 pm

Re: Why is the free running counter set to 3E?

Tue Dec 01, 2020 3:08 pm

trejan wrote:
Tue Dec 01, 2020 1:55 pm
Arm Ltd sells peripheral IP cores. The PL011 UARTs in the Pi SoC is one of them. SP804 is https://developer.arm.com/documentation/ddi0271/d/
My understanding so far: it seems the SP804 can safely be ignored. The Pi provides one AT (ARM Timer) and one FRC (Free Running Counter). The AT's frequency can be set, as can an interrupt. It is pointless to use the AT without an interrupt.

There's also an ST (System Timer), which ticks every 1microsecond. The FRC derives from the ST through a pre-scaler (maybe a couple).

So far so good?

So, in terms of interruptable timers, the Pi is pretty limited, it seems. You get one. I thought I read that it has 4 timers though, only 2 of which are accessable.

bzt
Posts: 607
Joined: Sat Oct 14, 2017 9:57 pm

Re: Why is the free running counter set to 3E?

Tue Dec 01, 2020 3:51 pm

blippy wrote:
Tue Dec 01, 2020 3:08 pm
The Pi provides one AT (ARM Timer) and one FRC (Free Running Counter).
Actually there are lot more. I had my own share with timer adventures. OSDev wiki lists at least 3 timers, and I've collected even more.
blippy wrote:
Tue Dec 01, 2020 3:08 pm
So, in terms of interruptable timers, the Pi is pretty limited, it seems.
I wouldn't call it limited, here's a list of the timers I know of (on RPi3 AArch64):

0x3F003000: BCM2835 Section 12, let's call this System Timer. This is one timer with four comparators, 0x3F00B204 bits 0-3, and first and third comparators are used by the GPU. Enabled by setting bits in 0x3F00B210 bits 0-3.
0x3F00B400: BCM2835 Section 14, SP408, let's call this TimerARM. This is one timer with one comparator, IRQ unknown (is this enabled by 0x3F00B218 bit 0? It should be I think).
0x40000034: QA7 Section 4.11, let's call this Local Timer. This is one timer with one comparator, IRQ in 0x40000070 + 4*X bit 11. Enabling should be connecting it with a Core in 0x40000024 (specifying X), and then writing the reload value and enable bits in 0x40000034.
0x40000040: QA7 Section 5.6, let's call them Core Timers. Four timers, comparator unknown (is this in CNTP_CVAL register? If so, what about the next timer?), IRQ in 0x40000070 + 4*N bit 1. It should be enabled by bits in 0x40000040. The most confusing part that this timer does not have Generic Timer registers, but it does have IRQ bits for the Generic Timer.
unknown: DDI0487 page D10-2653, let's call this Generic Timer. This has CNT system registers, which could be mapped in memory at an unknown address (not any of the above addresses, as neither of those has CNTFREQ register). Enabled by CNTP_CTL_EL0, comparator in CNTP_CVAL_EL0 as per D10-2653. IRQ unknown.
CNTFRQ, CNTPCT: ARM system registers, implemented in the CPU, not peripheral.

As far as I know, qemu emulates all the ARM system register timers and the QA7 Local Timer, but not the BCM System Timer.
blippy wrote:
Tue Dec 01, 2020 3:08 pm
It is pointless to use the AT without an interrupt.
Not necessarily. For small delays it's easier to poll, see here. It reads the CPU freq, calculates the deadline and then polls CNTPCT.

Cheers,
bzt

blippy
Posts: 123
Joined: Fri Nov 03, 2017 3:07 pm

Re: Why is the free running counter set to 3E?

Wed Dec 02, 2020 1:42 pm

This might be helpful to someone:

The APB (Advanced Peripheral Bus) operates at 250MHz on the Pi 3. So, apb_clock = 250000000 for the purposes of the formula in BCM2837 p199:
timer_clock = apb_clock/(pre_divider+1)
This formula is correct. The pre-divider is situated in base+0x41C, which has a default reset value of 0x07D (decimal 125) , giving a timer_clock of
timer_clock = 250e6/(125+1) = 1.98MHz (appox)
It seems an odd choice for a divider, but I think it's correct.

I found that as you want to increase the frequency of the timer, you should probably decrease the pre-divider. Otherwise you can get some quite inaccurate frequencies for the clock.

I also experimented with implementing my own "software clock" based on counting microseconds. My conclusion was that it was a terrible idea and very inaccurate. If you need to time things within fairly tight tolerances, then using a hardware timer is the only way to go.

I actually abandoned my cheapo Chinese oscilloscope as a way of measuring frequencies. It was too much of a chore. Instead, I used an Arduino Uno for that purpose. I started getting strange results around the 70kHz mark. My suspicion is that the Uno is not up to the task of coping with pin frequencies much above that. I'd need to try a beefier mcu, I think.

I found that all my victories have been hard-won. I imagine that most people sail through most of the difficulties I've faced.

Return to “Bare metal, Assembly language”