Import DSP56800 changes from SC.
[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.3  2004/06/06 18:30:34  bernie
19  * Import DSP56800 changes from SC.
20  *
21  * Revision 1.2  2004/06/03 11:27:09  bernie
22  * Add dual-license information.
23  *
24  * Revision 1.1  2004/05/23 18:23:30  bernie
25  * Import drv/timer module.
26  *
27  */
28
29 #ifndef DRV_TIMER_DSP56K_H
30 #define DRV_TIMER_DSP56K_H
31
32 #include <DSP56F807.h>
33 #include <compiler.h>
34 #include <hw.h>
35
36 // Calculate register pointer and irq vector from hw.h setting
37 #define REG_SYSTEM_TIMER          PP_CAT(REG_TIMER_, SYSTEM_TIMER)
38 #define SYSTEM_TIMER_IRQ_VECTOR   PP_CAT(IRQ_TIMER_, SYSTEM_TIMER)
39
40 //! Prescaler for the system timer
41 #define TIMER_PRESCALER           16
42
43 //! Frequency of the hardware high precision timer
44 #define TIMER_HW_HPTICKS_PER_SEC           (IPBUS_FREQ / TIMER_PRESCALER)
45
46 //! Type of time expressed in ticks of the hardware high precision timer
47 typedef uint16_t hptime_t;
48
49 static void timer_hw_init(void)
50 {
51         uint16_t compare;
52
53         // Clear compare flag status and enable interrupt on compare
54         REG_SYSTEM_TIMER->SCR &= ~REG_TIMER_SCR_TCF;
55         REG_SYSTEM_TIMER->SCR |= REG_TIMER_SCR_TCFIE;
56
57         // Calculate the compare value needed to generate an interrupt exactly
58         //  TICKS_PER_SEC times each second (usually, every millisecond). Check that
59         //  the calculation is accurate, otherwise there is a precision error
60         // (probably the prescaler is too big or too small).
61         compare = TIMER_HW_HPTICKS_PER_SEC / TICKS_PER_SEC;
62         ASSERT((uint32_t)compare * TICKS_PER_SEC == IPBUS_FREQ / TIMER_PRESCALER);
63         REG_SYSTEM_TIMER->CMP1 = compare;
64
65         // The value for reload (at initializationa and after compare is met) is zero
66         REG_SYSTEM_TIMER->LOAD = 0;
67
68         // Set the interrupt priority
69         irq_setpriority(SYSTEM_TIMER_IRQ_VECTOR, IRQ_PRIORITY_SYSTEM_TIMER);
70
71         // Small preprocessor trick to generate the REG_TIMER_CTRL_PRIMARY_IPBYNN macro
72         //  needed to set the prescaler
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 */