2b61e584a9c7d0856441c592e6236d6e5f6fa630
[bertos.git] / drv / timer_dsp56k.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2004 Giovanni Bajo
5  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
6  * All Rights Reserved.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Giovanni Bajo <rasky@develer.com>
12  *
13  * \brief Driver module for DSP56K
14  */
15
16 /*
17  * $Log$
18  * Revision 1.1  2004/05/23 18:23:30  bernie
19  * Import drv/timer module.
20  *
21  */
22
23 #ifndef DRV_TIMER_DSP56K_H
24 #define DRV_TIMER_DSP56K_H
25
26 #include <DSP56F807.h>
27 #include <compiler.h>
28
29 //! The system timer for events is currently TMRA0. We prefer A/B over C/D because
30 //  A/B share the pin with the quadrature decoder module, and we do not need
31 //  pins for our system timer.
32 //  If you want to change this setting, you need also to modify the IRQ vector table.
33 #define REG_SYSTEM_TIMER          (REG_TIMER_A + 0)
34 #define SYSTEM_TIMER_IRQ_VECTOR   42   /* TMRA0 */
35
36 #define TIMER_PRESCALER           16
37
38 //! Frequency of the hardware high precision timer
39 #define TIMER_HW_HPTICKS_PER_SEC           (IPBUS_FREQ / TIMER_PRESCALER)
40
41 //! Type of time expressed in ticks of the hardware high precision timer
42 typedef uint16_t hptime_t;
43
44 static void timer_hw_init(void)
45 {
46         uint16_t compare;
47
48         // Clear compare flag status and enable interrupt on compare
49         REG_SYSTEM_TIMER->SCR &= ~REG_TIMER_SCR_TCF;
50         REG_SYSTEM_TIMER->SCR |= REG_TIMER_SCR_TCFIE;
51
52         // Calculate the compare value needed to generate an interrupt exactly
53         //  TICKS_PER_SEC times each second (usually, every millisecond). Check that
54         //  the calculation is accurate, otherwise there is a precision error
55         // (probably the prescaler is too big or too small).
56         compare = TIMER_HW_HPTICKS_PER_SEC / TICKS_PER_SEC;
57         ASSERT((uint32_t)compare * TICKS_PER_SEC == IPBUS_FREQ / TIMER_PRESCALER);
58         REG_SYSTEM_TIMER->CMP1 = compare;
59
60         // The value for reload (at initializationa and after compare is met) is zero
61         REG_SYSTEM_TIMER->LOAD = 0;
62
63         // Set the interrupt priority
64         irq_setpriority(SYSTEM_TIMER_IRQ_VECTOR, IRQ_PRIORITY_SYSTEM_TIMER);
65
66         // Small preprocessor trick to generate the REG_TIMER_CTRL_PRIMARY_IPBYNN macro
67         //  needed to set the prescaler
68         #define PP_CAT2(x,y)                      x ## y
69         #define PP_CAT(x,y)                       PP_CAT2(x,y)
70         #define REG_CONTROL_PRESCALER             PP_CAT(REG_TIMER_CTRL_PRIMARY_IPBY, TIMER_PRESCALER)
71
72         // Setup the counter and start counting
73         REG_SYSTEM_TIMER->CTRL =
74                 REG_TIMER_CTRL_MODE_RISING    |          // count rising edges (normal)
75                 REG_CONTROL_PRESCALER         |          // frequency (IPbus / TIMER_PRESCALER)
76                 REG_TIMER_CTRL_LENGTH;                   // up to CMP1, then reload
77 }
78
79 INLINE void timer_hw_irq(void)
80 {
81         // Clear the overflow flag so that we are ready for another interrupt
82         REG_SYSTEM_TIMER->SCR &= ~REG_TIMER_SCR_TCF;
83 }
84
85 INLINE hptime_t timer_hw_hpread(void)
86 {
87         return REG_SYSTEM_TIMER->CNTR;
88 }
89
90 void system_timer_isr(void);
91
92 #define DEFINE_TIMER_ISR \
93         void system_timer_isr(void)
94
95 #endif /* DRV_TIMER_DSP56_H */