Page 1 of 1

multiple timers on RPi2?

Posted: Thu Feb 04, 2016 4:01 pm
by Bruce Jacob
I have been using the Local Timer as spec'ed in the BCM2836 doc "ARM Quad A7 core — Gert van Loo, 18 August 2014" for a countdown timer ... timer control is at 0x40000034, and I can get periodic interrupts just fine. My question is how can I get multiple timers, one on each of the four cores? Or at least two different ones if not four different ones.

Thank you!
Bruce

Re: multiple timers on RPi2?

Posted: Mon Feb 08, 2016 4:08 am
by Ultibo
Hi Bruce, The QA7 document does actually contain most of the info you need to get multiple timers per core, it just isn't always clear unless you also know about some other ARM specific info.

The Local Timer you have been using at 0x40000034 is a single timer only which seems to be implemented as part of the ARM control logic in the BCM2836, elsewhere in that document you will find references to CNTVIRQ / CNTHPIRQ / CNTPNSIRQ / CNTPSIRQ.

These are referring to the Generic Timer that is internal to each of the 4 Cortex A7s and are documented in the ARM Architecture Reference Manual itself, you need the ARMv7-A / ARMv7-M edition which can be found online if you search.

The registers at 0x40000040 to 0x4000004C allow you to enable IRQ/FIQ for each of the 4 timers on each of the 4 cores and interrupts are reported in the registers at 0x40000060 to 0x4000006C.

To actually set or read the timer counts and enable the timers you need to use MCR/MRC instructions to manipulate the values in the ARM control registers instead.

Of the 4 timers CNTV (Virtual Timer) , CNTHP (Hypervisor Timer), CNTPNS (Physical Non Secure Timer) and CNTPS (Physical Secure Timer) you can use at least 2 per core.

The non secure/secure versions of the physical timer are only available from the appropriate mode (Secure/Non Secure) so you can use one or the other, the virtual timer is usable in most cases and the hypervisor timer appears to be only usable from hypervisor mode.

Re: multiple timers on RPi2?

Posted: Mon Feb 08, 2016 3:17 pm
by Bruce Jacob
Fantastic -- thank you!

Re: multiple timers on RPi2?

Posted: Fri Feb 12, 2016 4:03 pm
by scarschtt
Hi, I'm using the BCM2836, i need a precise timer to read some GPIO inputs at certain intervals.
I have some code for BCM2835, but the register map us different on BCM2836.
where can I find some complete code examples on how to use hardware timer?
Can someone help me sending the code (I'm using C)?
Best regards.

Re: multiple timers on RPi2?

Posted: Mon Mar 07, 2016 3:28 pm
by Arjan
The best option for precise timing is using IRQ's. The example below let the ACT blink at 1Hz. And other code is executed at 40 Hz.

The definitions for BCM2835_ST can be found here https://github.com/vanvught/rpidmx512/b ... /bcm2835.h

Hope this helps.

Arjan
http://www.raspberrypi-dmx.com/

Code: Select all

void __attribute__((interrupt("IRQ"))) c_irq_handler(void) {
	dmb();

	if (BCM2835_ST->CS & BCM2835_ST_CS_M1) {
		BCM2835_ST->CS = BCM2835_ST_CS_M1;
		BCM2835_ST->C1 = BCM2835_ST->CLO + (uint32_t)25000;
              /* GPIO code */
	}

	if (BCM2835_ST->CS & BCM2835_ST_CS_M3) {
		BCM2835_ST->CS = BCM2835_ST_CS_M3;
		BCM2835_ST->C3 = BCM2835_ST->CLO + (uint32_t)1000000;
		hardware_led_set((int)(led_counter++ & 0x01));
	}

	dmb();
}

Code: Select all

	BCM2835_ST->C1 = BCM2835_ST->CLO + (uint32_t) 25000;
	BCM2835_ST->C3 = BCM2835_ST->CLO + (uint32_t) 1000000;
	BCM2835_ST->CS = BCM2835_ST_CS_M1 + BCM2835_ST_CS_M3;
	BCM2835_IRQ->IRQ_ENABLE1 = BCM2835_TIMER1_IRQn + BCM2835_TIMER3_IRQn;

	__enable_irq();

Re: multiple timers on RPi2?

Posted: Thu Mar 10, 2016 12:35 pm
by dradford
@arjan: IRQs aren't really the best option for precise timing (depending on how precise 'precise' needs to be). The latency is all over the place, especially if IRQs get disabled for any reason, or multiple interrupts need processing at the same time. IRQs are essentially assuming that the hardware is buffering data or using handshaking, or the speed is low enough for latency to be unimportant. FIQs are better, if accessing the gpio pins has to be done in the background (they were designed for reading data out of a latch before it gets overwritten by new data). Still not too precise. You could tie some pins together and use (say) PWM to generate a clock signal that you can use to latch an input, then follow up with an interrupt. But scarschtt's question implies a foreground loop, waiting for the timer to hit a value before manipulating the pin.

@scarschtt: The system timer is a peripheral, so is the same on all devices (see page 172 of the peripheral manual). If the addresses in the sample code are in the range 0x20003000..0x2000301b, that'll be what it is. The peripherals' base address has moved from 0x20000000 to 0x3f000000 on pi2/3, otherwise everything is the same (or has the clock freq changed on pi3?). On the other hand, if the particular timer you're looking at is ARM-side rather than a peripheral, you'll probably need to write new code. There are quite a few timers I'm afraid, running off various clocks. I believe some of the ARM timers are affected by the ARM's clock (so if the ARM's clock speed is reduced because of overheating, say, the timer will slow down too, or even stop if the processor is suspended - this is actually a benefit when profiling code).

[Also, when reading the system timer it's not possible to read the high and low words simultaneously, so the low word could wrap between reading low and high - very rare and you'll never be able to reproduce the bug! I normally read the timer like this: 1) B=hi; 2) A=lo; 3) C=hi; 4) if B==C, stop (timer is in A and B); 5) B=C; 6) goto 2.]