WXK
2024-09-18 05e2e954bd127de378a9d1dfbb0ed95d725aad63
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**************************************************************************//**
 * @file     timer.c
 * @version  V1.00
 * $Revision: 2 $
 * $Date: 16/02/24 15:37 $
 * @brief    Panchip series TIMER driver source file
 *
 * @note
 * Copyright (C) 2016 Panchip Technology Corp. All rights reserved.
*****************************************************************************/
#include "PanSeries.h"
#include "pan_timer.h"
#include "pan_clk.h"
 
/** @addtogroup Panchip_Device_Driver Panchip Device Driver
  @{
*/
 
/** @addtogroup Panchip_TIMER_Driver TIMER Driver
  @{
*/
 
 
/** @addtogroup Panchip_TIMER_EXPORTED_FUNCTIONS TIMER Exported Functions
  @{
*/
 
/**
  * @brief This API is used to configure timer to operate in specified mode
  *        and frequency. If timer cannot work in target frequency, a closest
  *        frequency will be chose and returned.
  * @param[in] timer The base address of Timer module
  * @param[in] cntMode Operation mode. Possible options are
  *                 - \ref TIMER_ONESHOT_MODE
  *                 - \ref TIMER_PERIODIC_MODE
  *                 - \ref TIMER_TOGGLE_MODE
  *                 - \ref TIMER_CONTINUOUS_MODE
  * @param[in] u32Freq Timer Target working frequency
  * @return Real Timer working frequency
  * @note After calling this API, Timer is \b NOT running yet. But could start timer running be calling
  *       \ref TIMER_Start macro or program registers directly
  */
uint32_t TIMER_Open(TIMER_T *timer, TIMER_CntModeDef cntMode, uint32_t u32Freq)
{
    uint32_t u32Clk = CLK_GetPeripheralFreq(timer);
    uint32_t u32Prescale = 0;
    uint32_t u32RealFreq = u32Freq;
 
    if (u32RealFreq > u32Clk)
        u32RealFreq = u32Clk;
    else if (u32RealFreq == 0)
        u32RealFreq = 1;
 
    u32Prescale = u32Clk / u32RealFreq - 1;
 
    if (u32Prescale > 0xFF)
        u32Prescale = 0xFF; //Prescale is 8bit in reg
 
    timer->CTL = ((timer->CTL & ~TIMER_CTL_PSC_Msk) |u32Prescale);
    timer->CTL = (( timer->CTL& ~TIMER_CTL_OPMODE_Msk)|cntMode);
 
    // Calc real frequency and return
    u32RealFreq = u32Clk / (u32Prescale + 1);
 
    return u32RealFreq;
}
 
/**
  * @brief This API stops Timer counting and disable the Timer interrupt function
  * @param[in] timer The base address of Timer module
  * @return None
  */
void TIMER_Close(TIMER_T *timer)
{
    timer->CTL = 0;
    timer->EXTCTL = 0;
 
}
 
/**
  * @brief This API is used to create a delay loop for u32usec micro seconds
  * @param[in] timer The base address of Timer module
  * @param[in] u32Usec Delay period in micro seconds with 10 usec every step. Valid values are between 10~1000000 (10 micro second ~ 1 second)
  * @return None
  * @note This API overwrites the register setting of the timer used to count the delay time.
  * @note This API use polling mode. So there is no need to enable interrupt for the timer module used to generate delay
  */
void TIMER_Delay(TIMER_T *timer, uint32_t u32Usec)
{
    uint32_t u32Clk = CLK_GetPeripheralFreq(timer);
    uint32_t u32Prescale = 0, delay = SystemCoreClock / u32Clk;
    float fCmpr;
 
    // Clear current timer configuration
    timer->CTL = 0;
    timer->EXTCTL = 0;
 
    if(u32Clk == 10000) {         // min delay is 100us if timer clock source is LIRC 10k
        u32Usec = ((u32Usec + 99) / 100) * 100;
    } else {    // 10 usec every step
        u32Usec = ((u32Usec + 9) / 10) * 10;
    }
 
    if(u32Clk >= 0x2000000) {
        u32Prescale = 3;    // real prescaler value is 4
        u32Clk >>= 2;
    } else if(u32Clk >= 0x1000000) {
        u32Prescale = 1;    // real prescaler value is 2
        u32Clk >>= 1;
    }
 
    
 
    // u32Usec * u32Clk might overflow if using uint32_t
    fCmpr = (float)u32Usec * u32Clk / 1000000.0f;
 
    timer->CMP = (uint32_t)fCmpr;
    timer->CTL = TIMER_CTL_CNTEN_Msk | u32Prescale; // one shot mode
 
    // When system clock is faster than timer clock, it is possible timer active bit cannot set in time while we check it.
    // And the while loop below return immediately, so put a tiny delay here allowing timer start counting and raise active flag.
    for(; delay > 0; delay--) {
        __NOP();
    }
 
    while(timer->CTL & TIMER_CTL_ACTSTS_Msk);
}
 
void TIMER_SetCmpValue(TIMER_T *timer, TIMER0_CmpSelDef cmp_seq, uint32_t u32Value)
{
    uint32_t cnt_per_apb_clks = 0, clk_src = 0;
    uint8_t psc_store_value = timer->CTL & TIMER_CTL_PSC_Msk;
    uint8_t compare_compensate = 0, remainder = FIXED_DEVIATION;
 
    /*count freq = apbclock / (psc + 1), so 1 hw timer count = (psc + 1) apb clks */
    cnt_per_apb_clks = psc_store_value + 1;
 
    if (timer == TIMER0) {
        clk_src = CLK->APB1_CLK_CTRL & CLK_APB1CLK_TMR0SRC_SEL_Msk;
    } else if(timer == TIMER1){
        clk_src = CLK->APB2_CLK_CTRL & CLK_APB2CLK_TMR1SRC_SEL_Msk;
    } else if(timer == TIMER2){
        clk_src = CLK->APB2_CLK_CTRL & CLK_APB2CLK_TMR2SRC_SEL_Msk;
    }
 
    /*timer clk source is apb clk */
    if (clk_src == 0) {
        if (FIXED_DEVIATION >= cnt_per_apb_clks) {
            compare_compensate = FIXED_DEVIATION / cnt_per_apb_clks;
            remainder = FIXED_DEVIATION - compare_compensate * cnt_per_apb_clks;
        }
        
        if (remainder * 2 >= cnt_per_apb_clks) {
            compare_compensate += 1;
        }
    }
 
    /*here has 12 apb clk for hw timer sync operation*/
    if (timer == TIMER0) {
        switch (cmp_seq) {
            case TMR0_COMPARATOR_SEL_CMP:
                timer->CMP = u32Value - compare_compensate;
                TIMER0->CTL |= (BIT0 << 8);
                break;
            case TMR0_COMPARATOR_SEL_CMP1: 
                timer->CMP1 = u32Value - compare_compensate;
                TIMER0->CTL |= (BIT1 << 8);
                break;
            case TMR0_COMPARATOR_SEL_CMP2: 
                timer->CMP2 = u32Value - compare_compensate;
                TIMER0->CTL |= (BIT2 << 8);
                break;
            default: 
                timer->CMP = u32Value - compare_compensate;
                break;
        }
    } else if ((timer == TIMER1) || (timer == TIMER2)){
        timer->CMP = u32Value - compare_compensate;
    }
}
 
/*@}*/ /* end of group Panchip_TIMER_EXPORTED_FUNCTIONS */
 
/*@}*/ /* end of group Panchip_TIMER_Driver */
 
/*@}*/ /* end of group Panchip_Device_Driver */
 
/*** (C) COPYRIGHT 2016 Panchip Technology Corp. ***/