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