[comp.sys.atari.st] Xbtimer

peterb@beldar.UUCP (05/14/87)

--

Ok, I give up. I've been battling the developers package documentation
long enough, so someone educate me:

I'm trying to get a 5Khz tick value by using Xbtimer(), and a service
routine. I kluged up a program to test this out, and its:

long tick=0;
int kick_count();

main()
{
	Xbtimer(0, 1, 122, &kick_count); /* gives a clock of 5039.xxx Hz */

	/* .. When I want the value of the tick, I just use tick */
}

kick_count() is in assembler which only increments tick. It does not
use any registers at all.

Of course the program doesn't run, and crashes after the call to Xbtimer().

Now the question: How do I get the damn thing to work?  Which return
do I use on my kick_count routine, and rts, rte, or an rtr? And do
I have to hack anything on the stack before the return to get this to work???

Help! I am going nuts!

Could some kind soul send me a code example, both for the call to Xbtimer()
and the little service routine to increment tick???

Thanx in advance,
--
Peter Barada
Xyvision, Inc.
(617)-245-4100
UUCP: ...!ihnp4!mirror!beldar!peterb

bammi@cwruecmp.UUCP (05/16/87)

In article <49500004@beldar> peterb@beldar.UUCP writes:
>
>--
>
>kick_count() is in assembler which only increments tick. It does not
>use any registers at all.
>
>Of course the program doesn't run, and crashes after the call to Xbtimer().
>
>Now the question: How do I get the damn thing to work?  Which return
>do I use on my kick_count routine, and rts, rte, or an rtr? And do
>I have to hack anything on the stack before the return to get this to work???
>

Peter,
	Sorry to reply here, but mirror bounced my mail back. Attached
below is a program that i did a while ago for a users group that shows
how to use Xbtimer(). A common mistake people make is to forget to reset
the bit in the ISR (see comments below). You need to return with an RTE
since the timer is interrupting.

							hope that helps,
-------
#include <osbind.h>
#include <stdio.h>

/* if using old version of Alcyon */
/* #define VOID int */
/* if using new (v4.14) of Alcyon */
#define VOID void

/*
 * Xbtimer.c
 *	Sample code that demonstrates the use of TIMER A on the 68901 MFP
 *	Also demonstrates  how to take over the process terminate interrupt.
 *
 *	WHAT:
 *
 *	The program begins by installing the address of the function
 *	'terminate' into the exception vector 0x102 (Process terminate
 *	exception, saving its old pointer. It then starts up Timer A on
 *	the MFP, configured to interrupt the function 'count' at 48Hz. The
 *	main loop continuously displays the value of a counter, that the
 *	function 'count' increments. On hitting CTRL-C, the 'terminate' function
 *	is called to handle the termination. It stops Timer A, then
 *	restores the origonal process terminate vector and
 *	returns (to the default system Interrupt Service Routine).
 *
 *	HOW:
 *	The timers on the MFP are controlled by a 2.4576 Mhz xtal (Yes the
 *	Atari Internals book is once again wrong!). Using
 *	timer 'a' in the delay mode with a prescale set at 200 (ie. by
 *	setting the timer 'a' control register to 7)
 *	gives you a 12288 Hz counter (2457600/200). Using a count
 *	of 256 (ie. by loading the timer 'a' data register with 0)
 *	you get an interrupt frequency of 48 Hz (12288/256). For other
 *	values for the control & data registers see the 68901 manual
 *	available for free by calling Motorola, or see the Atari Internals
 *	book.
 *
 *	The timer interrupt is handled by the function 'count'. This function
 *	increments the long counter, then clears Bit 5 of the ISRA (In
 *	Service Register A), and then returns from the exception by doing
 *	an RTE. NOTES: In the ST the 68901 always operates in the
 *	Software End of Interrupt Mode (ie. bit 3 of the Vector Register VR
 *	is always set). In this mode the ISR bit of the ISRA is automatically
 *	set when an interrupt occurs and the processor requests the interrupt
 *	vector. (The ISR bit corresponding to the Timer A interrupt is bit 5
 *	of the ISRA). As long as the bit is set, that interrupt and any other
 *	interrupts of lower priority cannot occur. Once the bit is cleared
 *	the same interrupt or any lower priority interrupts can once again
 *	occur. This is why it is important to clear BIT 5 of the ISRA before
 *	performing the RTE. The address of the ISRA register is 0xfffA0F
 *
 *
 *	Compile and link with gemstart.o, osbind.o, gemlib,  libf
 *
 *
 */

/* Static globals */

/* Internal software ticks counter */
long counter = 0L;

/* Saved Process terminate vector */
VOID (*t_handle)();

/* My process terminate handler */
VOID terminate()
{
	VOID count();

	/* Shut of Timer - by writing 0 to the control register of Timer A */
	Xbtimer(0, 0, 0, count);

	/* Clear bit 5 of ISRA just in case it was set */
	asm("bclr.b #5,$fffa0f");

	/* Restore the old process terminate vector */
	Setexc(0x0102, t_handle);

	/*
	 * by doing an RTS here we return to the systems default
	 * Interrupt service routine that dispatched the ^C interrupt
	 * to this routine. It will take care of doing the RTE
	 */

	/*
	 * Note that we could have done an unlk R4 to restore the stack frame
	 * and then jumped to the origonal handler too. (saved in t_handle)
	 *
	 */
}

/* MFP Timer A interrupt handler */
VOID count()
{
	/* Increment counter */
	counter++;

	/* Restore stack frame */
	asm("unlk R14");

	/* clear bit 5 of ISRA on the MFP */
	asm("bclr.b #5,$fffa0f");

	/* Return from exception */
	asm("rte");
}
	

/* Main */
main()
{
	
	/* Get current Process Terminate vector */
	t_handle = Setexc(0x0102, -1L);

	/* Set up our own Process Terminate Handler */
	Setexc(0x0102, terminate);

	/* Start the timer */
	Xbtimer(0, 7, 0, count);

	/* Continuously display counter */
	while(1 == 1)
	{
		char buf[12];

		sprintf(buf,"%09ld\r",counter);
		Cconws(buf);
	}

	/* If it gets here .. */
	Cconws("\r\nHeh! How did I end up here?\r\n");
}
-- 
usenet: {decvax,cbatt,cbosgd,sun}!cwruecmp!bammi	jwahar r. bammi
csnet:       bammi@case
arpa:        bammi%case@csnet-relay
compuServe:  71515,155