blade63(11)% more $pcex/timer.c
/* timer.c Test program to see timer running
* Build with $pcex/makefile: "make C=timer timer.exe"
*/
/* the makefile uses gcc -I<dir> to make sure these come from $pcinc-- */
#include <stdio.h>
#include <timer.h>
#define NTIMES 5
#define MAX 80
void smalldelay(void);
void showcounts();
void setcount(int count);
void main()
{
int count;
char buf[MAX];
printf("Enter count for timer (decimal no. <64K): ");
fgets(buf,MAX,CONSOLE); /* dev no. CONSOLE def'd in $pcinc/stdio.h */
sscanf(buf, "%d" ,&count);
setcount(count); /* 0 = max, 65536 */
showcounts();
showcounts();
showcounts();
}
/* about 10 usecs on a SAPC (400Mhz Pentium) */
void smalldelay(void)
{
int i;
for (i=0;i<1000;i++)
;
}
/* Print out timer counts after little delays, to show downcounting.
* Note we are assuming the calling overhead to outpt and inpt provide
* sufficient delay between the accesses to the same port */
void showcounts()
{
int i, count[NTIMES];
for (i=0;i<NTIMES;i++) {
/* command timer 0 to latch count: */
outpt(TIMER_CNTRL_PORT, TIMER0|TIMER_LATCH);
count[i] = inpt(TIMER0_COUNT_PORT); /* read in LSB of count */
count[i] |= inpt(TIMER0_COUNT_PORT)<<8; /* then MSB of count */
smalldelay();
}
for (i=0;i<NTIMES;i++) { /* this takes more time than "delay" */
printf("%d ",count[i]);
}
printf("\n");
}
/* set count to downcount from, in timer: it gets to 0, starts over */
void setcount(int count)
{
/* set timer 0 count, mode */
outpt(TIMER_CNTRL_PORT, TIMER0|TIMER_SET_ALL|TIMER_MODE_RATEGEN);
outpt(TIMER0_COUNT_PORT,count&0xff); /* set LSB here */
outpt(TIMER0_COUNT_PORT,count>>8); /* and MSB here */
smalldelay(); /* let timer have a moment */
}
blade63(12)% more $pcinc/timer.h
/* timer.h Header for Programmable Interrupt Timer */
#ifndef TIMER_H
#define TIMER_H
/* Timer 0 is wired to cause an interrupt when its count reaches zero */
#define TIMER0_COUNT_PORT 0x40
/* and that interrupt is irq 0 in the PIC */
#define TIMER0_IRQ 0
/* Timer 1 is set at bootup to help with RAM refresh, best to leave alone*/
/* Timer 2 is wired to speaker, so we can control pitch of sound */
#define TIMER2_COUNT_PORT 0x42
/* for commands to timers
* for example, to read the 16-bit counter in timer 0:
* --output TIMER0|TIMER_LATCH to TIMER_CNTRL_PORT, then
* --input a byte from TIMER_COUNT_PORT to get the low 8 bits of the count,
* --input another byte from TIMER_COUNT_PORT to get the high bits.
*/
#define TIMER_CNTRL_PORT 0x43
/* bits 6-7: which timer the command is for */
#define TIMER0 (0<<6)
#define TIMER1 (1<<6)
#define TIMER2 (2<<6)
/* bits 4-5: latch commands (take snapshot of counter and hold it for read) */
#define TIMER_LATCH (0<<4) /* latch current count bits 0-15, avail in two
8-bit reads (low bits, then high bits) */
#define TIMER_SET_LOW (1<<4) /* set bits 0-7 only */
#define TIMER_SET_HIGH (2<<4) /* set bits 8-15 only */
#define TIMER_SET_ALL (3<<4) /* set bits 0-15 (low bits, then high bits) */
/* bits 1-3: Mode select */
/* For the PC, the GATE input is wired high for timers 0 and 1, and to bit 0
* of port 0x61 for timer 2, so only timer 2 can effectively use the _GATE
* modes at all. The RATEGEN mode is best for timing. */
#define TIMER_MODE_1SHOT (0<<1) /* programmable one-shot, program init'd */
#define TIMER_MODE_1SHOT_GATE (1<<1) /* programmable one-shot, GATE input */
#define TIMER_MODE_RATEGEN (2<<1) /* rate generator (pulse train) */
#define TIMER_MODE_SQUAREWAVE (3<<1) /* low for count, hi for count, low...*/
#define TIMER_MODE_STROBE (4<<1) /* software-triggered pulse */
#define TIMER_MODE_STROBE_GATE (5<<1) /* GATE-triggered pulse */
/* bit 0: BCD select (BCD = binary coded decimal format for numbers) */
#define TIMER_BINARY_COUNTER 0
#define TIMER_BCD_COUNTER 1
#endif