Update to latest AVR timer code
authoraleph <aleph@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 7 Jun 2004 15:57:40 +0000 (15:57 +0000)
committeraleph <aleph@38d2e660-2303-0410-9eaa-f027e97ec537>
Mon, 7 Jun 2004 15:57:40 +0000 (15:57 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@35 38d2e660-2303-0410-9eaa-f027e97ec537

drv/timer_avr.h

index 296215db3625001841ae395bf1a0a1f370d798c8..cfcb86d84d2dbf7b9d02d246ae3bb11f4322f638 100755 (executable)
@@ -15,6 +15,9 @@
 
 /*
  * $Log$
+ * Revision 1.3  2004/06/07 15:57:40  aleph
+ * Update to latest AVR timer code
+ *
  * Revision 1.2  2004/06/03 11:27:09  bernie
  * Add dual-license information.
  *
 
 #include <avr/wdt.h>
 
-#      define TIMER_RETRIGGER /* Not needed, timer retriggers automatically  */
+#if (ARCH & ARCH_BOARD_KC)
+       #include <drv/adc.h>
+#endif
 
-       /*!
-        * System timer: additional division after the prescaler
-        * 12288000 / 64 / 192 (0..191) = 1 ms
-        */
-#      define OCR_DIVISOR 191
 
-       /*! HW dependent timer initialization  */
+#define timer_hw_irq()  /* Not needed, IRQ timer flag cleared automatically */
+
+/*!
+ * System timer: additional division after the prescaler
+ * 12288000 / 64 / 192 (0..191) = 1 ms
+ */
+#define OCR_DIVISOR 191
+
+/*! HW dependent timer initialization  */
 #if defined(CONFIG_TIMER_ON_TIMER0)
 
-#              define TIMER_INIT \
-               do { \
-                       DISABLE_INTS; \
-                       \
-                       /* Reset Timer flags */ \
-                       TIFR = BV(OCF0) | BV(TOV0); \
-                       \
-                       /* Setup Timer/Counter interrupt */ \
-                       ASSR = 0x00;                  /* internal system clock */ \
-                       TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64 */ \
-                       TCNT0 = 0x00;                 /* initialization of Timer/Counter */ \
-                       OCR0 = OCR_DIVISOR;           /* Timer/Counter Output Compare Register */ \
-                       \
-                       /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */ \
-                       TIMSK &= ~BV(TOIE0); \
-                       TIMSK |= BV(OCIE0); \
-                       \
-                       ENABLE_INTS; \
-               } while (0)
+       //! Type of time expressed in ticks of the hardware high-precision timer
+       typedef uint8_t hptime_t;
+
+       static void timer_hw_init(void)
+       {
+               cpuflags_t flags;
+               DISABLE_IRQSAVE(flags);
+
+               /* Reset Timer flags */
+               TIFR = BV(OCF0) | BV(TOV0);
+
+               /* Setup Timer/Counter interrupt */
+               ASSR = 0x00;                  /* internal system clock */
+               TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
+                                                prescaler change TIMER_HW_HPTICKS_PER_SEC too */
+               TCNT0 = 0x00;                 /* initialization of Timer/Counter */
+               OCR0 = OCR_DIVISOR;           /* Timer/Counter Output Compare Register */
+
+               /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
+               TIMSK &= ~BV(TOIE0);
+               TIMSK |= BV(OCIE0);
+
+               ENABLE_IRQRESTORE(flags);
+       }
+
+       //! Frequency of the hardware high precision timer
+       #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / 64)
+
+       INLINE hptime_t timer_hw_hpread(void);
+       INLINE hptime_t timer_hw_hpread(void)
+       {
+               return TCNT0;
+       }
 
 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
 
-#              define TIMER_INIT \
-               do { \
-                       DISABLE_INTS; \
-                       \
-                       /* Reset Timer overflow flag */ \
-                       TIFR |= BV(TOV1); \
-                       \
-                       /* Fast PWM mode, 24 kHz, no prescaling */ \
-                       TCCR1A |= BV(WGM11); \
-                       TCCR1A &= ~BV(WGM10); \
-                       TCCR1B |= BV(WGM12) | BV(CS10); \
-                       TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12)); \
-                       \
-                       TCNT1 = 0x00;         /* initialization of Timer/Counter */ \
-                       \
-                       /* Enable timer interrupt: Timer/Counter1 Overflow */ \
-                       TIMSK |= BV(TOIE1); \
-                       \
-                       ENABLE_INTS; \
-               } while (0)
+       //! Type of time expressed in ticks of the hardware high precision timer
+       typedef uint16_t hptime_t;
+
+       static void timer_hw_init(void)
+       {
+               cpuflags_t flags;
+               DISABLE_IRQSAVE(flags);
+
+               /* Reset Timer overflow flag */
+               TIFR |= BV(TOV1);
+
+               /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
+                  resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
+               TCCR1A |= BV(WGM11);
+               TCCR1A &= ~BV(WGM10);
+               TCCR1B |= BV(WGM12) | BV(CS10);
+               TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
+
+               TCNT1 = 0x00;         /* initialization of Timer/Counter */
+
+               /* Enable timer interrupt: Timer/Counter1 Overflow */
+               TIMSK |= BV(TOIE1);
+
+               ENABLE_IRQRESTORE(flags);
+       }
+
+       //! Frequency of the hardware high precision timer
+       #define TIMER_HW_HPTICKS_PER_SEC  (24000ul * 512)
+
+       INLINE hptime_t timer_hw_hpread(void);
+       INLINE hptime_t timer_hw_hpread(void)
+       {
+               return TCNT1;
+       }
 
 #elif defined(CONFIG_TIMER_ON_TIMER2)
 
-#              define TIMER_INIT \
-               do { \
-                       DISABLE_INTS; \
-                       \
-                       /* Reset Timer flags */ \
-                       TIFR = BV(OCF2) | BV(TOV2); \
-                       \
-                       /* Setup Timer/Counter interrupt */ \
-                       TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20); \
-                                             /* Clear on Compare match & prescaler = 64, internal sys clock */ \
-                       TCNT2 = 0x00;         /* initialization of Timer/Counter */ \
-                       OCR2 = OCR_DIVISOR;   /* Timer/Counter Output Compare Register */ \
-                       \
-                       /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */ \
-                       TIMSK &= ~BV(TOIE2); \
-                       TIMSK |= BV(OCIE2); \
-                       \
-                       ENABLE_INTS; \
-               } while (0)
+       //! Type of time expressed in ticks of the hardware high precision timer
+       typedef uint8_t hptime_t;
+
+       static void timer_hw_init(void)
+       {
+               cpuflags_t flags;
+               DISABLE_IRQSAVE(flags);
+
+               /* Reset Timer flags */
+               TIFR = BV(OCF2) | BV(TOV2);
+
+               /* Setup Timer/Counter interrupt */
+               TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
+               /* Clear on Compare match & prescaler = 64, internal sys clock.
+                  When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
+               TCNT2 = 0x00;         /* initialization of Timer/Counter */
+               OCR2 = OCR_DIVISOR;   /* Timer/Counter Output Compare Register */
+
+               /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
+               TIMSK &= ~BV(TOIE2);
+               TIMSK |= BV(OCIE2);
+
+               ENABLE_IRQRESTORE(flags);
+       }
+
+       //! Frequency of the hardware high precision timer
+       #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / 64)
+
+       INLINE hptime_t timer_hw_hpread(void);
+       INLINE hptime_t timer_hw_hpread(void)
+       {
+               return TCNT2;
+       }
 
 #else
-#              error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
+       #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
 #endif /* CONFIG_TIMER_ON_TIMERx */
 
 
 
        #define DEFINE_TIMER_ISR        \
                static void timer_handler(void)
+       
+       DEFINE_TIMER_ISR;
 
        /*
-       * Timer 1 overflow irq handler.
-       */
+        * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
+        * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
+        * handler is really a counter that call the true handler in timer.c
+        * every 1 ms.
+        */
        SIGNAL(SIG_OVERFLOW1)
        {
                /*!
-               * How many overflow we have to count before calling the true timer handler.
-               * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
-               * each call.
-               */
-       #define TIMER1_OVF_COUNT 24
+                * How many overflow we have to count before calling the true timer handler.
+                * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
+                * each call.
+                */
+               #define TIMER1_OVF_COUNT 24
 
                static uint8_t count = TIMER1_OVF_COUNT;
 
                        timer_handler();
                        count = TIMER1_OVF_COUNT;
                }
+
+       #if (ARCH & ARCH_BOARD_KC)
+               /*
+                * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
+                * of conversion (auto-triggered with timer 1 overflow).
+                * The switch can be done 2 ADC cycles after start of conversion.
+                * The handler prologue takes a little more than 32 CPU cycles: with
+                * the prescaler at 1/16 the timing should be correct even at the start
+                * of the handler.
+                *
+                * The switch is synchronized with the ADC handler using _adc_trigger_lock.
+                */
+               extern uint8_t _adc_idx_next;
+               extern bool _adc_trigger_lock;
+
+               if (!_adc_trigger_lock)
+               {
+                       TIMER_STROBE_ON;
+                       ADC_SETCHN(_adc_idx_next);
+                       TIMER_STROBE_OFF;
+                       _adc_trigger_lock = true;
+               }
+       #endif
        }
 
 #elif defined (CONFIG_TIMER_ON_TIMER0)
                SIGNAL(SIG_OUTPUT_COMPARE2)
 
 #else
-#      error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
+       #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
 #endif /* CONFIG_TIMER_ON_TIMERx */
 
 #endif /* DRV_TIMER_AVR_H */