• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* mbed Microcontroller Library
2  * Copyright (c) 2018-2019 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lp_ticker_api.h"
18 
19 #if DEVICE_LPTICKER
20 
21 /*******************************************************************************
22  * lp_ticker implementation on this target is mapped on top of the sleep clock counter
23  * that is running in the lowest energy modes. The sleep clock counter is 48b running
24  * at 32.768KHz. This gives 0.03ms resolution for the low power timer which requires
25  * millisecond accuracy.
26  *
27  ******************************************************************************/
28 
29 #include "reg_timer.h"
30 #include "sysctrl_api.h"
31 
32 static bool lp_ticker_inited = false;
33 
34 /// 3-part macro to function/variable/enum string
35 #define LPT_M2STR_P3_I(p0,p1,p2)    p0##p1##p2
36 #define LPT_M2STR_P3(p0,p1,p2)      LPT_M2STR_P3_I(p0, p1, p2)
37 
38 #define LP_TICKER_TIMER         CS_TIM2
39 #define LP_TICKER_TIMER_MRi     0
40 #define LP_TICKER_TIMER_IRQn    LPT_M2STR_P3(TIMER2, LP_TICKER_TIMER_MRi, _IRQn)
41 #define LP_TICKER_ISR_FUNC      LPT_M2STR_P3(TIMER2, LP_TICKER_TIMER_MRi, _IRQHandler)
42 
43 /// Match interrupt enable set
44 #define LPT_MINT_ENA_SET_BIT    (0x01UL << LP_TICKER_TIMER_MRi)
45 /// Wrap interrupt enable set
46 #define LPT_WINT_ENA_SET_BIT    (0x01UL << 7)
47 /// Match interrupt enable clear
48 #define LPT_MINT_ENA_CLR_BIT    (0x01UL << (8 + LP_TICKER_TIMER_MRi))
49 /// Wrap interrupt enable clear
50 #define LPT_WINT_ENA_CLR_BIT    (0x01UL << 15)
51 /// Match interrupt clear bit
52 #define LPT_MINT_CLR_BIT        (0x01UL << (16 + LP_TICKER_TIMER_MRi))
53 /// Wrap interrupt clear bit
54 #define LPT_WINT_CLR_BIT        (0x01UL << 23)
55 /// Match interrupt status masked bit
56 #define LPT_MINT_ST_MSK_BIT     (0x01UL << (8 + LP_TICKER_TIMER_MRi))
57 /// Wrap interrupt status masked bit
58 #define LPT_WINT_ST_MSK_BIT     (0x01UL << 15)
59 /// Match enable
60 #define LPT_MATCH_ENA_BIT       (0x01UL << (12 + LP_TICKER_TIMER_MRi))
61 
lp_ticker_get_info()62 const ticker_info_t *lp_ticker_get_info()
63 {
64     static const ticker_info_t info = {
65         1000000,    // 1MHz
66              32     // 32 bit counter
67     };
68     return &info;
69 }
70 
71 /** LP Ticker Interrupt Handler
72  *
73  * This function handles the lp ticker interrupt.
74  */
LP_TICKER_ISR_FUNC(void)75 void LP_TICKER_ISR_FUNC(void)
76 {
77     uint32_t status = LP_TICKER_TIMER->IS;
78     // wrap interrupt
79     if (status & LPT_WINT_ST_MSK_BIT) {
80         LP_TICKER_TIMER->IC = LPT_WINT_CLR_BIT; // clear interrupt
81     }
82     // match interrupt
83     if (status & LPT_MINT_ST_MSK_BIT) {
84         LP_TICKER_TIMER->IC = LPT_MINT_CLR_BIT; // clear interrupt
85         lp_ticker_irq_handler();
86     }
87 }
88 
lp_ticker_init()89 void lp_ticker_init()
90 {
91     if (lp_ticker_inited) {
92         /* calling init again should cancel current interrupt */
93         lp_ticker_disable_interrupt();
94         return;
95     }
96     lp_ticker_inited = true;
97 
98     if (pwrctrl_pwrmd_cpusys_sw_record_getf() == CPU_SYS_POWER_ON_RESET) {
99         uint32_t reg = LP_TICKER_TIMER->CTL;
100         if ((reg & 0x01UL) == 0x00UL) { // Init if disabled
101             const uint32_t tick_sel = 0x01UL;   // div2(64KHz)
102             LP_TICKER_TIMER->TCL = 0x00UL;      // time counter
103             LP_TICKER_TIMER->TCH = 0x00UL;
104             LP_TICKER_TIMER->TD =  tick_sel | (0x01UL << 4);
105             reg &= ~(0x03UL << 8);
106             reg |=  (0x01UL | (0x01UL << 5) | (tick_sel << 8)); // enable timer, ignore MR high-16bit, set tick freq
107             LP_TICKER_TIMER->CTL = reg;
108         }
109         if ((reg & LPT_MATCH_ENA_BIT) == 0x00UL) {
110             LP_TICKER_TIMER->CTL = reg | LPT_MATCH_ENA_BIT;  // enable match
111         }
112     }
113 
114     NVIC_SetPriority(LP_TICKER_TIMER_IRQn, __NVIC_PRIO_LOWEST);
115     NVIC_EnableIRQ(LP_TICKER_TIMER_IRQn);
116 }
117 
lp_ticker_free()118 void lp_ticker_free()
119 {
120     LP_TICKER_TIMER->CTL &= ~LPT_MATCH_ENA_BIT;    // disable match
121     LP_TICKER_TIMER->IC = LPT_MINT_ENA_CLR_BIT;
122     NVIC_DisableIRQ(LP_TICKER_TIMER_IRQn);
123 }
124 
lp_ticker_set_interrupt(timestamp_t timestamp)125 void lp_ticker_set_interrupt(timestamp_t timestamp)
126 {
127     // set match value
128     LP_TICKER_TIMER->MR[LP_TICKER_TIMER_MRi].L = (uint32_t)timestamp;
129     // enable match interrupt
130     LP_TICKER_TIMER->IC = LPT_MINT_ENA_SET_BIT;
131 }
132 
lp_ticker_fire_interrupt(void)133 void lp_ticker_fire_interrupt(void)
134 {
135     NVIC_SetPendingIRQ(LP_TICKER_TIMER_IRQn);
136 }
137 
lp_ticker_disable_interrupt()138 void lp_ticker_disable_interrupt()
139 {
140     LP_TICKER_TIMER->IC = LPT_MINT_ENA_CLR_BIT;
141 }
142 
lp_ticker_clear_interrupt()143 void lp_ticker_clear_interrupt()
144 {
145     LP_TICKER_TIMER->IC = LPT_MINT_CLR_BIT;
146 }
147 
lp_ticker_read()148 timestamp_t lp_ticker_read()
149 {
150     // Read forever until reaching two of the same
151     volatile unsigned long long read_previous, read_current;
152     do {
153         read_previous = LP_TICKER_TIMER->TCL;
154         read_current = LP_TICKER_TIMER->TCL;
155     } while (read_previous != read_current);
156 
157     return read_current;
158 }
159 
lp_ticker_read_time(uint32_t * msb,uint32_t * lsb)160 void lp_ticker_read_time(uint32_t *msb, uint32_t *lsb)
161 {
162     uint32_t _msb, _msb_r, _lsb;
163     _msb = LP_TICKER_TIMER->TCH;
164     _lsb = LP_TICKER_TIMER->TCL;
165     _msb_r = LP_TICKER_TIMER->TCH;
166 
167     if (_msb_r != _msb)
168     {
169         _lsb = LP_TICKER_TIMER->TCL;
170     }
171     *msb = _msb_r;
172     *lsb = _lsb;
173 }
174 
lp_ticker_set_match_time(uint32_t msb,uint32_t lsb)175 void lp_ticker_set_match_time(uint32_t msb, uint32_t lsb)
176 {
177     // set match value
178     LP_TICKER_TIMER->MR[LP_TICKER_TIMER_MRi].H = msb;
179     LP_TICKER_TIMER->MR[LP_TICKER_TIMER_MRi].L = lsb;
180     // enable match interrupt
181     LP_TICKER_TIMER->IC = LPT_MINT_ENA_SET_BIT;
182 }
183 
lp_ticker_set_match_time_lo(uint32_t time)184 void lp_ticker_set_match_time_lo(uint32_t time)
185 {
186     LP_TICKER_TIMER->MR[LP_TICKER_TIMER_MRi].L = time; // set match value
187     LP_TICKER_TIMER->IC = LPT_MINT_ENA_SET_BIT; // enable match interrupt
188 }
189 
190 
lp_ticker_set_ignore_tc_hi(int ignore)191 void lp_ticker_set_ignore_tc_hi(int ignore)
192 {
193     if (ignore) {
194         LP_TICKER_TIMER->CTL |=  (0x01UL << 5);
195     } else {
196         LP_TICKER_TIMER->CTL &= ~(0x01UL << 5);
197     }
198 }
199 
lp_ticker_time_cmp(uint32_t time1,uint32_t time2)200 bool lp_ticker_time_cmp(uint32_t time1, uint32_t time2)
201 {
202     uint32_t diff = time1 - time2;
203     return (((int32_t)diff) < 0);
204 }
205 
lp_ticker_time_past(uint32_t time)206 bool lp_ticker_time_past(uint32_t time)
207 {
208     uint32_t _lsb = LP_TICKER_TIMER->TCL;
209     return (lp_ticker_time_cmp(time, _lsb));
210 }
211 
212 #endif /* DEVICE_LPTICKER */
213