Interrupts and Timers

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
urchin
Posts: 121
Joined: Thu Jun 02, 2005 5:41 pm

Interrupts and Timers

Post by urchin »

PSP_VBLANK_INT

The vblank interrupt triggers every 1/60 second. Using the following function:

Code: Select all

	int sceKernelRegisterSubIntrHandler(int intno, int no, void *handler, void *arg);
up to 16 individual subinterrupt handlers may be installed for the vblank interrupt (intno = PSP_VBLANK_INT, no = 0 - 15). The prototype for vblank handler functions is:

Code: Select all

	void vblank_handler(int sub, void* arg);
where "sub" is the subinterrupt number and "arg" is the arg parameter passed in during the register function. Registering more than one subinterrupt handler is probably not very useful for vblank, but may be useful for others. Before calling QueryIntrHandlerInfo, the PspIntrHandlerOptionParam "size" field must be initialised with sizeof(PspIntrHandlerOptionParam). Calling the function yields the following info:

Code: Select all

	enabled = 0 / 1 -> disabled / enabled
	calls = number of times handler has been called since registration
	intr_code = interrupt number, e.g. 0x1e = PSP_VBLANK_INT
	common = "common" parameter pass during handler registration
	entry = handler function pointer
	intr_level = 3 (?)
Attempting to register PSP_VBLANK_INT with subinterrupt PSP_DISPLAY_SUBINT results in failure (as PSP_DISPLAY_SUBINT > 15), suggesting that the PspSubInterrupts enum or my use of it may be incorrect.

PSP_SYSTIMER(N)_INT

Calls to register or enable on these interrupts always yield 0x80020065 (illegal intr code), which seems plausible if they are system interrupts. QueryIntrHandlerInfo yields the following interesting information:

Code: Select all

	min_clock_low = 0xFFFFFFFF
	min_clock_hi = 0xFFFFFFFF
	max_clock_low = 0x00000000
	max_clock_hi = 0x00000000
	enabled = always 0
	gp = 0x88052FB0
	entry = 0x8804A4E2
	common = 0x8804AF30 for timer #0, (#1 -> AF50, #2 -> AF70, #3 -> AF90)
The "entry" and "common" addresses appear to map into the "SysTimerForKernel" module, but not to any of the known functions.

VTimers

VTimers are configurable virtual timers that are called from system interrupts, possibly PSP_SYSTIMER(N)_INT. sceKernelCreateVTimer returns the UID of a new timer. I managed to create 1300 timers before my PSP asploded, but I didn't try to use them all. The upper limit may be imposed by the size of the UID table. Timer resolution is in microseconds and calling sceKernelGetVTimerTime before the timer has started returns 0. Each timer can be started using the sceKernelStartVTimer using the UID returned from sceKernelCreateVTimer.

The sceKernelSetVTimerHandler function is used to register a handler with the timer. In user mode, simply pass in the address of the function. When called from kernel mode, the handler seems to be required to reside in kernel space (> 0x80000000) otherwise registration fails with a return code of 0x800200D3 (illegal address). Adding 0x80000000 to the address of the handler seems to work well. Kernel mode can be detected by checking the "attr" field of the current thread's info struct.

When registering the timer, the "time" parameter indicates the period before the handler is triggered (assuming the timer is started from zero)

The handler prototype is:

Code: Select all

	SceUInt vtimer_handler(SceUID uid, SceKernelSysClock* requested, SceKernelSysClock* actual, void* common);
where "uid" is UID of the timer, "requested" is the requested callback time, "actual" is the actual time it was called (e.g. requested may be 1000, but actual 1015) and "common" is the common parameter passed in during handler registration. Set the return code of the handler to the period desired before the handler is called again. If set to 0, the handler will not be called. Note that the handler is called from an interrupt, so thread related functions and others such as printf may not be used.

btw, this research was sponsored by psplink :)
kasikeeper
Posts: 36
Joined: Thu Nov 29, 2007 7:08 pm

Post by kasikeeper »

Hi,

I tried out the code outline given above and the timer interrupts work just fine. However as you said already ...
Note that the handler is called from an interrupt, so thread related functions and others such as printf may not be used.
... some fancier stuff like putting up a psp message dialog box do not work inside my callback function. Do you know what is required to make that possible. I guess some kind of a thread maybe but I am unsure.

Kai
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

kasikeeper wrote:Hi,

I tried out the code outline given above and the timer interrupts work just fine. However as you said already ...
Note that the handler is called from an interrupt, so thread related functions and others such as printf may not be used.
... some fancier stuff like putting up a psp message dialog box do not work inside my callback function. Do you know what is required to make that possible. I guess some kind of a thread maybe but I am unsure.

Kai
you shouldn't use any blocking functions (functions that can switch thread) in a callback. If you need so, you must create a thread and an event (or a semaphore, a messagebox, etc.). Your thread just needs to wait for this event to run your blocking functions in a loop. Your callback just sets an event to wakeup this thread.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Can you set the semaphore inside the interrupt handler? That would be handy for things that want to delay on the vertical blank - just add the handler and at the proper place, just wait on the semaphore.
kasikeeper
Posts: 36
Joined: Thu Nov 29, 2007 7:08 pm

Post by kasikeeper »

Thanks a lot four your help so far. I followed up on the thread approach and successfully created my thread which I call from the timer callback. Now the problem is the my thread is not started from my timer callback. The timer callback is triggered properly but

Code: Select all

sceKernelStartThread(EventAlarmThreadID, 0, 0);
does not start my thread. I did put the sceKernelStartThread(EventAlarmThreadID, 0, 0); statement in other places of my program just to make sure my thread works at all and it does indeed work alright. But for some reason it does not start my thread from within the timer callback. No error messages or something. sceKernelStartThread returns a number other than the thread id but not 0 or -1 so I guess it should be fine. Does anyone know???
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

huh i'm not sure about what you wanted to do...

say, you have a main thread.

Initially, your main thread is creating your Alarm thread and your Alarm event. Just let your main tread to start your Alarm thread once, before triggering any Alarm callbacks.

The code to run in your Alarm thread is quite simple : a loop which waits for the Alarm event. When an event wakes up the Alarm thread, and conditions are okay for a thread switch to occur and elect your Alarm thread, the Alarm thread exits from the event wait function : here you must put your code to run then loop again when finished so the Alarm thread waits for the next Alarm event.

Your Alarm callback, when running, just sets an Alarm event then exits the callback : you should not start a thread here.

The Alarm thread must have a higher priority than the main thread, so it can have more chance to be elected just after exiting interrupt. Don't expect a thread switch in a interrupt, this is a silly idea. Your callback is just a deferred call to wake up a higher prioritized but shorter thread which will be elected as soon as possible (i.e, when a thread switch can occur).

There is no way else.
kasikeeper
Posts: 36
Joined: Thu Nov 29, 2007 7:08 pm

Post by kasikeeper »

Thanks a lot for all your help. I got it running and my timer works perfectly now. Now I want my timer to continue working also in sleep mode and - once the callback is triggered - I want the PSP to wake from sleep mode to do something.

From another thread I learned that the PSP's RTC functionality would allow to create timers that continue working in sleep mode. I checked the corresponding header file psprtc.h but could not find timer handle functionality. Where is the RTC / sleep&wake functionality hidden. Can you give me some clues?
Post Reply