📄 timer.c
字号:
/* * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. * * 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 */#include <common.h>#include <commproc.h>#include <mpc8xx_irq.h>#include <exports.h>DECLARE_GLOBAL_DATA_PTR;#undef DEBUG#define TIMER_PERIOD 1000000 /* 1 second clock */static void timer_handler (void *arg);/* Access functions for the Machine State Register */static __inline__ unsigned long get_msr(void){ unsigned long msr; asm volatile("mfmsr %0" : "=r" (msr) :); return msr;}static __inline__ void set_msr(unsigned long msr){ asm volatile("mtmsr %0" : : "r" (msr));}/* * Definitions to access the CPM Timer registers * See 8xx_immap.h for Internal Memory Map layout, * and commproc.h for CPM Interrupt vectors (aka "IRQ"s) */typedef struct tid_8xx_cpmtimer_s { int cpm_vec; /* CPM Interrupt Vector for this timer */ ushort *tgcrp; /* Pointer to Timer Global Config Reg. */ ushort *tmrp; /* Pointer to Timer Mode Register */ ushort *trrp; /* Pointer to Timer Reference Register */ ushort *tcrp; /* Pointer to Timer Capture Register */ ushort *tcnp; /* Pointer to Timer Counter Register */ ushort *terp; /* Pointer to Timer Event Register */} tid_8xx_cpmtimer_t;#ifndef CLOCKRATE# define CLOCKRATE 64#endif#define CPMT_CLOCK_DIV 16#define CPMT_MAX_PRESCALER 256#define CPMT_MAX_REFERENCE 65535 /* max. unsigned short */#define CPMT_MAX_TICKS (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER)#define CPMT_MAX_TICKS_WITH_DIV (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER * CPMT_CLOCK_DIV)#define CPMT_MAX_INTERVAL (CPMT_MAX_TICKS_WITH_DIV / CLOCKRATE)/* For now: always use max. prescaler value */#define CPMT_PRESCALER (CPMT_MAX_PRESCALER)/* CPM Timer Event Register Bits */#define CPMT_EVENT_CAP 0x0001 /* Capture Event */#define CPMT_EVENT_REF 0x0002 /* Reference Counter Event *//* CPM Timer Global Config Register */#define CPMT_GCR_RST 0x0001 /* Reset Timer */#define CPMT_GCR_STP 0x0002 /* Stop Timer */#define CPMT_GCR_FRZ 0x0004 /* Freeze Timer */#define CPMT_GCR_GM_CAS 0x0008 /* Gate Mode / Cascade Timers */#define CPMT_GCR_MASK (CPMT_GCR_RST|CPMT_GCR_STP|CPMT_GCR_FRZ|CPMT_GCR_GM_CAS)/* CPM Timer Mode register */#define CPMT_MR_GE 0x0001 /* Gate Enable */#define CPMT_MR_ICLK_CASC 0x0000 /* Clock internally cascaded */#define CPMT_MR_ICLK_CLK 0x0002 /* Clock = system clock */#define CPMT_MR_ICLK_CLKDIV 0x0004 /* Clock = system clock / 16 */#define CPMT_MR_ICLK_TIN 0x0006 /* Clock = TINx signal */#define CPMT_MR_FRR 0x0008 /* Free Run / Restart */#define CPMT_MR_ORI 0x0010 /* Out. Reference Interrupt En. */#define CPMT_MR_OM 0x0020 /* Output Mode */#define CPMT_MR_CE_DIS 0x0000 /* Capture/Interrupt disabled */#define CPMT_MR_CE_RISE 0x0040 /* Capt./Interr. on rising TIN */#define CPMT_MR_CE_FALL 0x0080 /* Capt./Interr. on falling TIN */#define CPMT_MR_CE_ANY 0x00C0 /* Capt./Interr. on any TIN edge*//* * which CPM timer to use - index starts at 0 (= timer 1) */#define TID_TIMER_ID 0 /* use CPM timer 1 */void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval);static char *usage = "\n[q, b, e, ?] ";int timer (int argc, char *argv[]){ cpmtimer8xx_t *cpmtimerp; /* Pointer to the CPM Timer structure */ tid_8xx_cpmtimer_t hw; tid_8xx_cpmtimer_t *hwp = &hw; int c; int running; app_startup(argv); /* Pointer to CPM Timer structure */ cpmtimerp = &((immap_t *) gd->bd->bi_immr_base)->im_cpmtimer; printf ("TIMERS=0x%x\n", (unsigned) cpmtimerp); /* Initialize pointers depending on which timer we use */ switch (TID_TIMER_ID) { case 0: hwp->tmrp = &(cpmtimerp->cpmt_tmr1); hwp->trrp = &(cpmtimerp->cpmt_trr1); hwp->tcrp = &(cpmtimerp->cpmt_tcr1); hwp->tcnp = &(cpmtimerp->cpmt_tcn1); hwp->terp = &(cpmtimerp->cpmt_ter1); hwp->cpm_vec = CPMVEC_TIMER1; break; case 1: hwp->tmrp = &(cpmtimerp->cpmt_tmr2); hwp->trrp = &(cpmtimerp->cpmt_trr2); hwp->tcrp = &(cpmtimerp->cpmt_tcr2); hwp->tcnp = &(cpmtimerp->cpmt_tcn2); hwp->terp = &(cpmtimerp->cpmt_ter2); hwp->cpm_vec = CPMVEC_TIMER2; break; case 2: hwp->tmrp = &(cpmtimerp->cpmt_tmr3); hwp->trrp = &(cpmtimerp->cpmt_trr3); hwp->tcrp = &(cpmtimerp->cpmt_tcr3); hwp->tcnp = &(cpmtimerp->cpmt_tcn3); hwp->terp = &(cpmtimerp->cpmt_ter3); hwp->cpm_vec = CPMVEC_TIMER3; break; case 3: hwp->tmrp = &(cpmtimerp->cpmt_tmr4); hwp->trrp = &(cpmtimerp->cpmt_trr4); hwp->tcrp = &(cpmtimerp->cpmt_tcr4); hwp->tcnp = &(cpmtimerp->cpmt_tcn4); hwp->terp = &(cpmtimerp->cpmt_ter4); hwp->cpm_vec = CPMVEC_TIMER4; break; } hwp->tgcrp = &cpmtimerp->cpmt_tgcr; printf ("Using timer %d\n" "tgcr @ 0x%x, tmr @ 0x%x, trr @ 0x%x," " tcr @ 0x%x, tcn @ 0x%x, ter @ 0x%x\n", TID_TIMER_ID + 1, (unsigned) hwp->tgcrp, (unsigned) hwp->tmrp, (unsigned) hwp->trrp, (unsigned) hwp->tcrp, (unsigned) hwp->tcnp, (unsigned) hwp->terp ); /* reset timer */ *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); /* clear all events */ *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF); printf (usage); running = 0; while ((c = getc()) != 'q') { if (c == 'b') { setPeriod (hwp, TIMER_PERIOD); /* Set period and start ticking */ /* Install interrupt handler (enable timer in CIMR) */ install_hdlr (hwp->cpm_vec, timer_handler, hwp); printf ("Enabling timer\n"); /* enable timer */ *hwp->tgcrp |= (CPMT_GCR_RST << TID_TIMER_ID); running = 1;#ifdef DEBUG printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," " tcr=0x%x, tcn=0x%x, ter=0x%x\n", *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, *hwp->tcrp, *hwp->tcnp, *hwp->terp );#endif } else if (c == 'e') { printf ("Stopping timer\n"); *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); running = 0;#ifdef DEBUG printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," " tcr=0x%x, tcn=0x%x, ter=0x%x\n", *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, *hwp->tcrp, *hwp->tcnp, *hwp->terp );#endif /* Uninstall interrupt handler */ free_hdlr (hwp->cpm_vec); } else if (c == '?') {#ifdef DEBUG cpic8xx_t *cpm_icp = &((immap_t *) gd->bd->bi_immr_base)->im_cpic; sysconf8xx_t *siup = &((immap_t *) gd->bd->bi_immr_base)->im_siu_conf;#endif printf ("\ntgcr=0x%x, tmr=0x%x, trr=0x%x," " tcr=0x%x, tcn=0x%x, ter=0x%x\n", *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, *hwp->tcrp, *hwp->tcnp, *hwp->terp );#ifdef DEBUG printf ("SIUMCR=0x%08lx, SYPCR=0x%08lx," " SIMASK=0x%08lx, SIPEND=0x%08lx\n", siup->sc_siumcr, siup->sc_sypcr, siup->sc_simask, siup->sc_sipend ); printf ("CIMR=0x%08lx, CICR=0x%08lx, CIPR=0x%08lx\n", cpm_icp->cpic_cimr, cpm_icp->cpic_cicr, cpm_icp->cpic_cipr );#endif } else { printf ("\nEnter: q - quit, b - start timer, e - stop timer, ? - get status\n"); } printf (usage); } if (running) { printf ("Stopping timer\n"); *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID); free_hdlr (hwp->cpm_vec); } return (0);}/* Set period in microseconds and start. * Truncate to maximum period if more than this is requested - but warn about it. */void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval){ unsigned short prescaler; unsigned long ticks; printf ("Set interval %ld us\n", interval); /* Warn if requesting longer period than possible */ if (interval > CPMT_MAX_INTERVAL) { printf ("Truncate interval %ld to maximum (%d)\n", interval, CPMT_MAX_INTERVAL); interval = CPMT_MAX_INTERVAL; } /* * Check if we want to use clock divider: * Since the reference counter can be incremented only in integer steps, * we try to keep it as big as possible to allow the resulting period to be * as precise as possible. */ /* prescaler, enable interrupt, restart after ref count is reached */ prescaler = (ushort) ((CPMT_PRESCALER - 1) << 8) | CPMT_MR_ORI | CPMT_MR_FRR; ticks = ((ulong) CLOCKRATE * interval); if (ticks > CPMT_MAX_TICKS) { ticks /= CPMT_CLOCK_DIV; prescaler |= CPMT_MR_ICLK_CLKDIV; /* use system clock divided by 16 */ } else { prescaler |= CPMT_MR_ICLK_CLK; /* use system clock without divider */ }#ifdef DEBUG printf ("clock/%d, prescale factor %d, reference %ld, ticks %ld\n", (ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1, CPMT_PRESCALER, (ticks / CPMT_PRESCALER), ticks );#endif /* set prescaler register */ *hwp->tmrp = prescaler; /* clear timer counter */ *hwp->tcnp = 0; /* set reference register */ *hwp->trrp = (unsigned short) (ticks / CPMT_PRESCALER);#ifdef DEBUG printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x," " tcr=0x%x, tcn=0x%x, ter=0x%x\n", *hwp->tgcrp, *hwp->tmrp, *hwp->trrp, *hwp->tcrp, *hwp->tcnp, *hwp->terp );#endif}/* * Handler for CPMVEC_TIMER1 interrupt */staticvoid timer_handler (void *arg){ tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)arg; /* printf ("** TER1=%04x ** ", *hwp->terp); */ /* just for demonstration */ printf ("."); /* clear all possible events: Ref. and Cap. */ *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -