diff options
Diffstat (limited to 'nuttx/arch/sh/src/sh1/sh1_timerisr.c')
-rw-r--r-- | nuttx/arch/sh/src/sh1/sh1_timerisr.c | 104 |
1 files changed, 95 insertions, 9 deletions
diff --git a/nuttx/arch/sh/src/sh1/sh1_timerisr.c b/nuttx/arch/sh/src/sh1/sh1_timerisr.c index 874e25647..01113b390 100644 --- a/nuttx/arch/sh/src/sh1/sh1_timerisr.c +++ b/nuttx/arch/sh/src/sh1/sh1_timerisr.c @@ -58,7 +58,58 @@ * CLK_TCK (see include/time.h). CLK_TCK defines the desired number of * system clock ticks per second. That value is a user configurable setting * that defaults to 100 (100 ticks per second = 10 MS interval). + * + * ITU1 operates in periodic timer mode. TCNT counts up until it matches + * the value of GRA0, then an interrupt is generated. Two values must be + * computed: + * + * (1) The divider that determines the rate at which TCNT increments, and + * (2) The value of GRA0 that cause the interrupt to occur. + * + * These must be selected so that the frequency of interrupt generation is + * CLK_TCK. Ideally, we would like to use the full range of GRA0 for better + * timing acuracy: + */ + +#define DESIRED_GRA0 65535 + +/* The ideal divider would be one that generates exactly 65535 ticks in + * 1/CLK_TCK seconds. For example, if SH1_CLOCK is 10MHz and CLK_TCK is + * 100, then the ideal divider must be less greater than or equal to: + * + * (10,000,000 / CLK_TCK) / 65535 = 1.525 + * + * The actual selected divider would then have to be 2, resulting in a + * counting rate of 5,000,0000 and a GRA0 setting of 50,000. */ + +#define SYSCLKS_PER_TICK ((SH1_CLOCK + (CLK_TCK-1))/ CLK_TCK) +#define DESIRED_DIVIDER ((SYSCLKS_PER_TICK + (DESIRED_GRA0-1))/ DESIRED_GRA0) + +#if (DESIRED_DIVIDER <= 1) +# define SYSCLK_DIVIDER 1 +# define SH1_ITUTCR_DIV SH1_ITUTCR_DIV1 +#elif (DESIRED_DIVIDER <= 2) +# define SYSCLK_DIVIDER 2 +# define SH1_ITUTCR_DIV SH1_ITUTCR_DIV2 +#elif (DESIRED_DIVIDER <= 4) +# define SYSCLK_DIVIDER 4 +# define SH1_ITUTCR_DIV SH1_ITUTCR_DIV4 +#elif (DESIRED_DIVIDER <= 8) +# define SYSCLK_DIVIDER 8 +# define SH1_ITUTCR_DIV SH1_ITUTCR_DIV8 +#else +# error "No divider is available for this system clock" +#endif + +/* The TCNT will then increment at the following rate: */ + +#define TCNT_CLOCK ((SH1_CLOCK + (SYSCLK_DIVIDER/2))/ SYSCLK_DIVIDER) + +/* And the value of GRA0 that generates at CLK_TCK ticks per second is: */ + +#define TCNT_PER_TICK ((TCNT_CLOCK + (CLK_TCK-1))/ CLK_TCK) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -82,9 +133,18 @@ int up_timerisr(int irq, uint32 *regs) { + ubyte reg8; + /* Process timer interrupt */ sched_process_timer(); + + /* Clear ITU0 interrupt status flag */ + + reg8 = getreg8(SH1_ITU0_TSR); + reg8 &= ~SH1_ITUTSR_IMFA; + putreg8(reg8, SH1_ITU0_TSR); + return 0; } @@ -99,19 +159,45 @@ int up_timerisr(int irq, uint32 *regs) void up_timerinit(void) { -#warning "Timer initialization logic needed" -#if 0 + ubyte reg8; - /* Set the IRQ interrupt priority */ + /* Clear timer counter 0 */ - up_prioritize_irq(STR71X_IRQ_SYSTIMER, 1); + putreg16(0, SH1_ITU0_TCNT); - /* Attach the timer interrupt vector */ + /* Set the GRA0 match value. The interrupt will be generated when TNCT + * increments to this value + */ - (void)irq_attach(STR71X_IRQ_SYSTIMER, (xcpt_t)up_timerisr); + putreg16(TCNT_PER_TICK, SH1_ITU0_GRA); - /* And enable the timer interrupt */ + /* Set the timer control register. TCNT cleared by FRA */ - up_enable_irq(STR71X_IRQ_SYSTIMER); -#endif + putreg8(SH1_ITUTCR_CGRA|SH1_ITUTCR_DIV, SH1_ITU0_TCR); + + /* Set the timer I/O control register */ + + putreg8(0, SH1_ITU0_TIOR); /* GRA used but with no inputs/output pins */ + + /* Make sure that all status flags are clear */ + + putreg8(0, SH1_ITU0_TSR); + + /* Attach the IMIA0 IRQ */ + + irq_attach(SH1_SYSTIMER_IRQ, (xcpt_t)up_timerisr); + + /* Enabled interrupts from GRA compare match */ + + putreg8(SH1_ITUTIER_IMIEA, SH1_ITU0_TIER); + + /* Set the interrupt priority */ + + up_prioritize_irq(SH1_SYSTIMER_IRQ, 7); /* Set ITU priority midway */ + + /* Start the timer */ + + reg8 = getreg8(SH1_ITU_TSTR); + reg8 |= SH1_ITUTSTR_STR0; /* Enable TCNT0 */ + putreg8(reg8, SH1_ITU_TSTR); /* TCNT0 is counting */ } |