User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

[BareMetal] Timer on Raspi

Sun Jul 01, 2012 8:49 am

Hi,

i have a question on understanding the architecture. In the BCM document it says that the SP804 has only one timer.
On the other hand i find the system timer and the arm timer.

So are there 3 timers? Or more? In the linux source i find the following (irqs.h):

Code: Select all

#define IRQ_TIMER0            (IRQ_ARMCTRL_START + INTERRUPT_TIMER0)
#define IRQ_TIMER1            (IRQ_ARMCTRL_START + INTERRUPT_TIMER1)
#define IRQ_TIMER2            (IRQ_ARMCTRL_START + INTERRUPT_TIMER2)
#define IRQ_TIMER3            (IRQ_ARMCTRL_START + INTERRUPT_TIMER3)

#define IRQ_ARM_TIMER         (IRQ_ARMCTRL_START + INTERRUPT_ARM_TIMER)
5 Timer Interrupts?! And no sign of the "System Timer"-Int from the BCM document.
Can someone help? Thanks

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 8:55 am

Oh and if ound the following thing:

platform.h

Code: Select all

#define MAX_TIMER                       2
#define MAX_PERIOD                      699050
#define TICKS_PER_uSEC                  1
Really strange

dom
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 5370
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 9:45 am

There is a GPU timer which has 4 comparison registers, and 4 interrupts.
There is an ARM timer interrupt.

The ARM timer is derived from the GPU core clock, which unless you force it (with core_freq= in config.txt) is variable due to power management, so not much use as a timer.
So, linux uses the GPU timer for its interrupts.
Note the GPU uses timers 0 and 2. 3 is reserved for linux, so would be most suitable for a bare metal OS. 1 is currently unallocated, so could be used.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 10:14 am

Hi Dom,

thanks, and where is this SystemTimer the BCM documents talks about in chapter 12, at what INT he comes from?

At the moment I did this:

Code: Select all

	WRITE32(ARMTIMER_CONTROL, 0x00000000);
	WRITE32(ARMTIMER_PREDIV, 0x000000f9);
	WRITE32(ARMTIMER_RELOAD,0x 4C4B40); //50 times a Sec by 250Mhz
	WRITE32(ARMTIMER_LOAD, 0x4C4B40);//50 times a Sec by 250Mhz
	WRITE32(ARMTIMER_IRQ_ACK, 0x00000000);
	WRITE32(ARMTIMER_CONTROL, 0x000000a2);
	WRITE32(ARM_IRQ_ENBL3, 0x00000001);	
So you say I should capture the IRQ_TIMER3? And how can i program it? Cant find anything about it in the BCM doc.

dom
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 5370
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 11:24 am

https://github.com/raspberrypi/linux/bl ... /bcm2708.c

Search for timer, and all should be revealed.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 2:29 pm

Thanks again, pops up the next question:
/* STC: a free running counter that increments at the rate of 1MHz */

1Mhz of what counter? core = 250? arm = 700?

dom
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 5370
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 2:38 pm

Cycl0ne wrote:Thanks again, pops up the next question:
/* STC: a free running counter that increments at the rate of 1MHz */

1Mhz of what counter? core = 250? arm = 700?
Just 1MHz. It increments every microsecond. It comes from a different PLL than ARM or GPU core.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Sun Jul 01, 2012 2:45 pm

Ahh ok microsecond and not Mhz ;-) i thought of something like: 1/700 sec per one increase. when i read the comment.

Thanks again ;)

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Fri Jul 06, 2012 12:08 pm

Hi Don,

last Question on this Subject, everything works now really cool. What i am not sure about:

Code: Select all

	UINT32	IRQBits = READ32(ARM_IRQ_PEND3);

	if (CHECK_BIT(IRQBits, 8)) 
	{
		IRQBits = READ32(ARM_IRQ_PEND1);
		UINT32 number = MultiplyDeBruijnBitPosition2[(UINT32)(IRQBits * 0x077CB531U) >> 27];

		ForeachNode(&SysBase->IRQServer[number], irq)
		{
			if (irq->is_Handler(number, istate, irq->is_Data)) 
			{
				irq->is_Count++;
				break;
			}
		}
		WRITE32(ARM_IRQ_PEND3, 0x00000000); // Not sure?!
		WRITE32(ARM_IRQ_PEND1, 0x00000000); // Not sure?!
those Comments: // Not Sure?!
Is it a must to "clear" both pending registers?

The timer works really cool and i also implemented the other timer for "time critical" things on demand. Thanks for the tips.

dwelch67
Posts: 961
Joined: Sat May 26, 2012 5:32 pm

Re: [BareMetal] Timer on Raspi

Wed Jul 11, 2012 2:52 am

http://github.com/dwelch67/raspberrypi

I have examples using the supposedly single timer. They call it a single timer but it is two timers one freerunning and the other with a few more features. (somewhere in the blinker examples I try the two timers).

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: [BareMetal] Timer on Raspi

Wed Jul 11, 2012 7:03 am

Hi Dwelch,

here is the code for the timer, they have 4 timers free running on 4 channels. 2 channels are reserved for the VideoCore.

Here the IRQ Code to reinitialise the timer:

Code: Select all

__attribute__((no_instrument_function))  UINT32 IRQ_Tick(unsigned int exc_no, istate *istate, APTR Data, SysBase *SysBase)
{
	WRITE32(ST_BASE + 0x00, 1<<3);
	UINT32 stc = READ32(ST_BASE + 0x04);
	WRITE32(ST_BASE + 0x18, stc + STC_FREQ_HZ/50); // We are running here with 1usecond per increase 50 taskswitch per second

	Schedule();
	return 1;
}
and here the initialisation code:

Code: Select all

	WRITE32(ARM_T_CONTROL, 0x00000000);
//	SysBase->IRQHandler[IRQ_TIMER3] = &IRQ_Tick;
	UINT32 stc = READ32(ST_BASE + 0x04);
	WRITE32(ST_BASE+0x18, stc + STC_FREQ_HZ/50);
	WRITE32(ARM_T_CONTROL, 1<<5);
	WRITE32(ARM_IRQ_ENBL1, 1<<3);
	WRITE32(ARM_IRQ_PEND1, 0x00000000);
This is TIMER_3 you can also user TIMER_1 independently.

What i am not sure about is the following in my IRQ Server code:

Code: Select all

		WRITE32(ARM_IRQ_PEND3, 0x00000000); // Not sure?!
		WRITE32(ARM_IRQ_PEND1, 0x00000000); // Not sure?!
if i need to clear both pending registers.

if you want to read the timer without getting into a interrupt:

Code: Select all

UINT32 ReadEClock(struct EClockVal *src)
{
	src->ev_lo = READ32(ST_BASE+0x04);
	src->ev_hi = READ32(ST_BASE+0x08);
	return STC_FREQ_HZ;
}

Return to “Bare metal, Assembly language”