GP32 Interrupts


pea

developer
Joined
Oct 3, 2004
Messages
1,089
Age
46
Location
New Zealand
Website
www.projectitis.com
Hi all,

I want to set up an interrupt to handle the mouse routines on GPDesktop for two reasons:
1) The mouse needs to move the same speed no matter which clock speed is used
2) The mouse still needs to move if something is using a lot of processing time (i.e. I can't just have a while() loop to wait x time).

How do interrupts work? Are they based on CPU cycles (e.g. fire every 1000 cycles) or LCD vsyncs (e.g. fire when LCD gets to line 200) or real time (e.g. fire every 20 ms) or something else?

AND.. does an interrupt just run a function I specify?

I want to do something like this e.g.:

Code:
function handleInput(){
  pauseInterrupts();

  exit_if_not_enough_time_has_passed();  
  do_mouse_stuff();

  continueInterrupts();
}

disable_interrupts();
insert_my_interrupt( handleInput );
enableInterrupts();

Is my thinking sort of right, or am i way off the mark? Where can I see a good working example of this?

p.s. I can link it to the RTC for timing if necessary. tsk tsk Mr.Mirko, whhy would you use a global variable called 'in_use'. Not very specific is it :(
 
An example of how to setup an use timer 4 is provided here:

http://www.cs.helsinki.fi/u/jikorhon/condev/gp32/dl/vblank.c

ARM timers (and pretty much every other processor I've used) all run on CPU cycles and just call a function you specify. This does mean however that the timing will change if you change the cpu speed, so you'll need to recalibrate the values to put in the timer every time you change the cpu speed.

If you don't want the timing to change with the processor speed, then I think the only other option is the RTC interrupt, which mirko uses already. Just remove his and use your own.

From what you want to do however, maybe you should be using some kind of RTOS, and have the mouse update as another task?
 
Hi all,

I want to set up an interrupt to handle the mouse routines on GPDesktop for two reasons:
1) The mouse needs to move the same speed no matter which clock speed is used
2) The mouse still needs to move if something is using a lot of processing time (i.e. I can't just have a while() loop to wait x time).

How do interrupts work? Are they based on CPU cycles (e.g. fire every 1000 cycles) or LCD vsyncs (e.g. fire when LCD gets to line 200) or real time (e.g. fire every 20 ms) or something else?

AND.. does an interrupt just run a function I specify?

I want to do something like this e.g.:

Code:
function handleInput(){
  pauseInterrupts();

  exit_if_not_enough_time_has_passed();  
  do_mouse_stuff();

  continueInterrupts();
}

disable_interrupts();
insert_my_interrupt( handleInput );
enableInterrupts();

Is my thinking sort of right, or am i way off the mark? Where can I see a good working example of this?

p.s. I can link it to the RTC for timing if necessary. tsk tsk Mr.Mirko, whhy would you use a global variable called 'in_use'. Not very specific is it :(


tsk tsk...

static char in_use=0; is a global variable ?

static means, thats it only readable in this *.c file, so its not a global variable, its a local
variable to see if the RTC is in use or not.

greets, Mirko
 
Last edited by a moderator:
That looks very interesting.... I'll see if I can use it. But I will still need a timer based interrupt for the mouse. I will probably run it using the RTC interrupt.

BTW - If a function is called by an interrupt, can that interrupt be fired while the original interrupt function is still running? What happens in this case? Does the original simply terminate, never to continue, or does the original interrupt continue after the second has completed?

e.g.
Code:
// IDEAL EXAMPLE
running_code
interrupt_fired -> run_interrupt
  interrupt_finished
continue running code

// NOT SO GOOD EXAMPLE 1
running_code
interrupt_fired -> run_interrupt
  interrupt_fired -> run_interrupt
    interrupt_finished
  interrupt_finished
continue running code

// EVEN WORSE EXAMPLE 2
running_code
interrupt_fired -> run_interrupt
  interrupt_fired -> run_interrupt (first one aborted)
    interrupt_finished
continue running code
 
Although I'm not sure whether the arm supports concurrent interrupts (I assume it does), I wouldn't worry. Each interrupt will execute fully before it can be run again (concurrent interrupts usually have to be on different vectors, and can normally be disabled anyway).

So, you could have something like this:

Interrupt occurs.
Interrupt runs.
Interrupt is ready to trigger, but is held off.
Interrupt finishes.
Pending interrupt from above occurs.
Interrupt runs.
Interrupt finishes.
continue running code
etc.

Worst case is that the interrupt can immediately trigger after exiting the previous interrupt, so no non-interrupt code is run. Just make sure this doesn't happen (do whatever is required to reset the interrupt condition before exiting).
 
Please let me know how this turns out, I'm trying to do the same thing. (use a timer interrupt to run mouse code)

Except I don't have a darned clue how to use the timers. Which timers do Mr.Mirko's SDK use? I think it uses one to simulate v-sync, but I'm not sure if the remaning 4 are unused... the mod player uses a timer, so that's two...

In my program, I can just adjust the rate of the timer whenever the user selects a different clock speed.
 
Code:
/*
 * Realtimeclock driver - gp_timer.c
 *
 * Copyright (C) 2003,2004 Mirko Roller <mirko@mirkoroller.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Changelog:
 *
 *  21 Aug 2004 - Mirko Roller <mirko@mirkoroller.de>
 *   first release 
 *
 */


#include "gp32.h"

static char in_use=0;
volatile u32 rGLOBALCOUNTER;

static void RTCInt(void) __attribute__ ((interrupt ("IRQ")));
static void RTCInt(void) {
   rGLOBALCOUNTER++;
  // Do all youre little IRQ stuff here, like moving a pointer over the screen :)
  // like get key status, move mouse, display mouse... 
  // Make shure youre little event is small, and will not use more then 1/64 seconds in time.
  // This function is cpuclock independent, so the mouse will move the same spped, not depending on CPU clock.
}

static
void setupRTCInt( void ) {
   // enable RTC
   rCLKCON |= 0x800;
   //
   // The CPU clock indepentent RTC Timer
   //
   // The ticnt register 0x15700044 (32 bit) offers:
   //
   // BIT   7: 0=disable 1=enable timer
   // BIT 0-6: tick time count value 1-127
   //
   // %10000000 should result in a 1/128 timer, but is not working
   // %10000001 result in 1/64 timer
   // %11111111 result in 1/1  timer
   
   rTICINT = 0x81;
   rGLOBALCOUNTER = 0;
}

static
void InstallRTC( void ) {
   gp_disableIRQ();
   gp_installSWIIRQ(8,RTCInt);
   gp_enableIRQ();
}

u32 gp_getRTC() {
   return rGLOBALCOUNTER;
}

void gp_initRTC() {
   if (in_use == 0) {
      setupRTCInt();
      InstallRTC();
      in_use=1;
   }
}

void gp_clearRTC() {
   rGLOBALCOUNTER=0;
}
 
Squidge - does the hardware know that the interrupt routine is running and hold off firing the interrupt again, or do I have to manually disable the interrupt and enable it again afterwards?
 
Drag,

I modified and recompiled Mr.Mirkos SDK to add a callback (event) into the RTC code. What this means is that you can pass the rtcInit function the pointer to your custom functuion, and every tick count the RTC code will also call your function.

The new code is:
Code:
#include "gp32.h"

static char in_use=0;
volatile u32 rGLOBALCOUNTER;
// 'fOntick' is now a pointer to a function that takes an unsigned long
// as an argument, and returns nothing.
static void (*fOnTick)(unsigned long); 

static void RTCInt(void) __attribute__ ((interrupt ("IRQ")));
static void RTCInt(void) {
   rGLOBALCOUNTER++;
   // If a callback is defined, call it with the tick count
   if (fOnTick!=NULL){ fOnTick(rGLOBALCOUNTER); }
}

static
void setupRTCInt( void ) {
   // enable RTC
   rCLKCON |= 0x800;
   //
   // The CPU clock indepentent RTC Timer
   //
   // The ticnt register 0x15700044 (32 bit) offers:
   //
   // BIT   7: 0=disable 1=enable timer
   // BIT 0-6: tick time count value 1-127
   //
   // %10000000 should result in a 1/128 timer, but is not working
   // %10000001 result in 1/64 timer
   // %11111111 result in 1/1  timer
   
   rTICINT = 0x81;
   rGLOBALCOUNTER = 0;
}

static
void InstallRTC( void ) {
   gp_disableIRQ();
   gp_installSWIIRQ(8,RTCInt);
   gp_enableIRQ();
}

u32 gp_getRTC() {
   return rGLOBALCOUNTER;
}

void gp_initRTC( void (*eOnTick)(unsigned long) ) {
   if (in_use == 0) {
    	fOnTick = eOnTick; // Set callback to point to custom event
      setupRTCInt();
      InstallRTC();
      in_use=1;
   }
}

void gp_clearRTC() {
   rGLOBALCOUNTER=0;
}

You use it like this:
Code:
// Define your event/callback function
void onTickCount( unsigned long tick ){
  // do something
}

// Init the RTC
gp_initRTC( onTickCount);
gp_clearRTC();

I haven't fully tested it, but it compiles and runs ok. Just to be sure, I would make sure that you don't put much time consuming code in the callback.
 
Squidge - does the hardware know that the interrupt routine is running and hold off firing the interrupt again, or do I have to manually disable the interrupt and enable it again afterwards?

It knows. If the interrupt occurs again whilst you are still in the interrupt routine, the interrupt will be latched into the interrupt pending register, but will not fire until the current interrupt has finished.
 
Last edited by a moderator:
Ah, sorry but I got mine working already. I just have the RTC counter running and within my while(1) loop, I have it checking to see if a certain amount of ticks have gone by, and I run code in there. My mouse pointer is working perfectly. I have 3 buffers: 1 is the BG, and 2 are for sprites. Every time the screen is updated (which is done in the RTC routine), I toggle the screen pointer between buffers 2 and 3. Then, I have dma channel 0 copy the BG buffer to the sprite buffer that isn't currently being displayed, I wait for the DMA to finish, and then draw the sprites. Flickerless from what I can tell, except in GeePee32 (in GeePee32, random columns of the cursor sprite flicker at times), but I don't take that emulator very seriously anymore. I should also mention I'm using 8bit screen mode. :p

On an unrelated note, GeePee32 is horribly inaccurate. o_O You know... just in case anyone doesn't know yet. :p

Also, when you're setting up a timer's tick count, what order do the bits go in? 10000001 = 1/64, so does 10000010 = 1/48?
 
According to the comments in Mr.Mirkos code:
Code:
  // %10000000 should result in a 1/128 timer, but is not working
  // %10000001 result in 1/64 timer
  // %11111111 result in 1/1  timer

Therefore:

Code:
// %10000000 should result in a 1/128 timer, but is not working
// %10000001 result in 1/64 timer
// %10000011 result in 1/32 timer
// %10000111 result in 1/16 timer
// %10001111 result in 1/8 timer
// %10011111 result in 1/4 timer
// %10111111 result in 1/2 timer
// %11111111 result in 1/1  timer

// %10000101 result in 1/48  timer ?

Or not?
 
rTICINT is a counter and the interrupt occurs when the counter reaches zero, so the period of the interrupt is:

( value + 1 ) / 128 second

So, %10000101 (value = 5) result in 1/21 timer
 
Maybe the internal hardware uses a counter, and you can't increase the counter by 0. :p

But yes, thank you, the period formula will be helpful to know.
Except I don't need a timer quite yet under the circumstances, but I should know how to use one so I don't get intimidated by it. :p
 
Fishing up old posts again:

Has someone got an example of how to set up an interrupt (using Mr.Mirkos SDK) NOT based on the RTC?

A few questions:

1) How is this done (setting up a simple interrupt in c)?
2) How many interrupts can be set up?
3) Which ones are used internally and can't be touched (if any)?
 
Back
Top