Skip to content. | Skip to navigation

Personal tools

lcu/timers.c

lcu/timers.c

lcu/timers.c

///////////////////////////////////////////////////////////
// Routines to handle hardware timers

#include <stdlib.h>
#include <conio.h>
#include <stdio.h>

#include "common.h"
#include "timers.h"
#include "clocks.h"

#define T0CNT   0xFF30  //control port for timer 0
#define T0CMPA  0xFF32  //first reset count for timer 0
#define T0CMPB  0xFF34  //second reset count for timer 0
#define T0CON   0xFF36  //timer 0 counter

#define T1CNT   0xFF38
#define T1CMPA  0xFF3A
#define T1CMPB  0xFF3C
#define T1CON   0xFF3E

//timer 2 have only one reset count
#define T2CNT   0xFF40
#define T2CMPA  0xFF42
#define T2CON   0xFF46

//configuration word
//configured to fire an interrupt when the counter equals the comparison record,
//to use the CPU clock, use cmpA as comparison record,
//no prescaling, run continuously
//don't start the timer yet
#define CONFW   0xE001


///////////////////////////////////////////////////////////
// InitTimer:
//      Initialize a timer in continuous mode using only one
//      comparison record
// Inputs:
//      st: pointer to a timer struct to hold data
//      t: timer to use (0,1,2)
//      f: desired interrupt frequency of the timer.

int
InitTimer(struct timer *st, int t, int f)
{
    //assign the apropiate control ports
    printf("Initializing timer %d\n",t);
    switch (t) {
        case 0:
            st->cnt = T0CNT;
            st->cmpA = T0CMPA;
            st->cmpB = T0CMPB;
            st->con = T0CON;
            st->clocks = NULL;
            break;
        case 1:
            st->cnt = T1CNT;
            st->cmpA = T1CMPA;
            st->cmpB = T1CMPB;
            st->con = T1CON;
            st->clocks = NULL;
            break;
        case 2:
            st->cnt = T2CNT;
            st->cmpA = T2CMPA;
            st->cmpB = 0;       //timer 2 doesn't have a second comparison record
            st->con = T2CON;
            st->clocks = NULL;
            break;
        default:
            return 0;
    }
    printf("Ports for timer %d:\n",t);
    printf("cnt:%X\n",st->cnt);
    printf("cmpA:%X\n",st->cmpA);
    printf("cmpB:%X\n",st->cmpB);
    printf("con:%X\n",st->con);

    //the frequency
    st->freq = f;
    printf("freq:%d\n",st->freq);

    //calculate every how many ticks an interruption should be issued
    //a timer is increased every fourth tick of the CPU by hardware
    st->tcksPInt = (CPUCLK/4)/f;
    printf("tcksPInt:%d\n",st->tcksPInt);

    //calculate the reminder of the previous division.
    //the remining ticks must be interpolated to avoid clock drifting
    st->tcksRmdr = (CPUCLK/4)%f;
    printf("tcksRmdr:%d\n",st->tcksRmdr);

    //calculate every how many interrupts do we have to interpolate a
    //remaining tick
    //it doesn't matter if the division is not exact 
    //if tcksRmdr is greater than 0, a tick is added at the beginning
    //of every cycle, so all the remaining ticks are added within the
    //cycle anyway at more or less regular intervals
    if (st->tcksRmdr > 0) {
        st->intPRem = f / st->tcksRmdr;
    } else {
        st->intPRem = 0;
    }
    printf("intPRem:%d\n",st->intPRem);


    //interrupt accumulator
    //the accumulator is increased with every interruption, up until intPRem,
    //an extra tick is added to the next interruption, then reset to 0 and start over.
    st->intAcc = 0;
    printf("intAcc:%d\n",st->intAcc);

    //configure the comparison record, we use only one comparison record
    //if the frequency doesn't divide exactly the tick rate, start with an extra tick
    if (st->tcksRmdr > 0) {
        printf("Writing %d to %X\n",st->tcksPInt+1,st->cmpA);
        outpw(st->cmpA, st->tcksPInt+1);
    } else {
        printf("Writing %d to %X\n",st->tcksPInt,st->cmpA);
        outpw(st->cmpA, st->tcksPInt);
    }

    //configure the timer writing to the control port
    printf("Writing %016b to %X\n",CONFW,st->cnt);
    outpw(st->cnt,CONFW);

    //no clocks driven at this moment
    st->clocks = NULL;

    printf("timer initialization finished\n");
    return 1;
}

void
ReportTimer(struct timer *t)
{
    printf("%X: %016b\n",t->cnt,inpw(t->cnt));
    printf("%X: %d\n",t->cmpA,inpw(t->cmpA));
    printf("freq: %d\n",t->freq);
    printf("Ticks per int: %d\n",t->tcksPInt);
    printf("Ticks reminding: %d\n",t->tcksRmdr);
    printf("Interrupts per reminder: %d\n",t->intPRem);
    printf("Interrupts accumulator: %d\n",t->intAcc);
}

void __interrupt __far timerInt()
{
}


Generated by GNU Enscript 1.6.5.2.
Document Actions