forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Interrupts and Timers

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
urchin



Joined: 02 Jun 2005
Posts: 121

PostPosted: Tue May 09, 2006 4:58 pm    Post subject: Interrupts and Timers Reply with quote

PSP_VBLANK_INT

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

Code:
   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:
   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:
   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:
   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:
   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 :)
Back to top
View user's profile Send private message
kasikeeper



Joined: 29 Nov 2007
Posts: 36

PostPosted: Wed Mar 05, 2008 7:33 am    Post subject: Reply with quote

Hi,

I tried out the code outline given above and the timer interrupts work just fine. However as you said already ...

Quote:
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
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Wed Mar 05, 2008 9:20 am    Post subject: Reply with quote

kasikeeper wrote:
Hi,

I tried out the code outline given above and the timer interrupts work just fine. However as you said already ...

Quote:
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.
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Wed Mar 05, 2008 9:46 am    Post subject: Reply with quote

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.
Back to top
View user's profile Send private message AIM Address
kasikeeper



Joined: 29 Nov 2007
Posts: 36

PostPosted: Thu Mar 06, 2008 5:43 am    Post subject: Reply with quote

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:
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???
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Thu Mar 06, 2008 7:45 am    Post subject: Reply with quote

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.
Back to top
View user's profile Send private message
kasikeeper



Joined: 29 Nov 2007
Posts: 36

PostPosted: Tue Mar 11, 2008 12:02 am    Post subject: Reply with quote

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?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group