• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <stdio.h>
17 #include <errno.h>
18 #include "duet_cm4.h"
19 #include "duet.h"
20 #include "duet_timer.h"
21 
22 duet_timer_cb_t g_duet_timer_handler[DUET_TIMER_NUM];
23 
TIMER_IRQHandler(void)24 void TIMER_IRQHandler(void)
25 {
26     //    duet_intrpt_enter();
27     if (TIMER1->MIS) {
28         TIMER1->INTCLR = 1; // clear irq
29         if (g_duet_timer_handler[DUET_TIMER1_INDEX].cb) {
30             g_duet_timer_handler[DUET_TIMER1_INDEX].cb(g_duet_timer_handler[DUET_TIMER1_INDEX].arg);
31         }
32     }
33     if (TIMER2->MIS) {
34         TIMER2->INTCLR = 1; // clear irq
35         if (g_duet_timer_handler[DUET_TIMER2_INDEX].cb) {
36             g_duet_timer_handler[DUET_TIMER2_INDEX].cb(g_duet_timer_handler[DUET_TIMER2_INDEX].arg);
37         }
38     }
39     //    duet_intrpt_exit();
40 }
41 
42 /**
43  * init a hardware timer
44  *
45  * @param[in]  tmr         timer struct
46  * @param[in]  period      micro seconds for repeat timer trigger
47  * @param[in]  auto_reoad  set to 0, if you just need oneshot timer
48  * @param[in]  cb          callback to be triggered after useconds
49  * @param[in]  ch          timer channel
50  * @param[in]  arg         passed to cb
51  */
duet_timer_init(duet_timer_dev_t * tim)52 int32_t duet_timer_init(duet_timer_dev_t *tim)
53 {
54     uint8_t timer_mode;
55     uint32_t reg_value;
56     uint32_t system_clock = SYSTEM_CLOCK;
57 
58     if (NULL == tim) {
59         return EIO;
60     }
61     if (tim->port >= DUET_TIMER_NUM) {
62         return EIO;
63     }
64     // Set Timer Clock Enable
65     reg_value = REG_RD(PERI_CLK_EN_REG1) & (~TIMER_BUS_CLK_BIT);
66     REG_WR(PERI_CLK_EN_REG1, (reg_value | (TIMER_BUS_CLK_BIT)));
67     if (TIMER_RELOAD_AUTO == tim->config.reload_mode) {
68         timer_mode = PERIODIC_MODE;
69     } else if (TIMER_RELOAD_MANU == tim->config.reload_mode) {
70         timer_mode = ONE_SHOT_MODE;
71     } else {
72         return EIO;
73     }
74     g_duet_timer_handler[tim->port].cb = tim->config.cb;
75     g_duet_timer_handler[tim->port].arg = tim->config.arg;
76     if (DUET_TIMER1_INDEX == tim->port) {
77         TIMER1->CONTROL = TIMER_DISABLE; // disable timer first
78         TIMER1->LOAD = tim->config.period * (system_clock / 1000000); // 1000000 for us
79         TIMER1->CONTROL |= (TIMER_PRESCALE | TIMER_SIZE | timer_mode); // timer control
80     } else { // if(DUET_TIMER2_INDEX == tim->port)
81         TIMER2->CONTROL = TIMER_DISABLE; // disable timer first
82         TIMER2->LOAD = tim->config.period * (system_clock / 1000000); // 1000000 for us
83         TIMER2->CONTROL |= (TIMER_PRESCALE | TIMER_SIZE | timer_mode); // timer control
84     }
85     return 0;
86 }
87 
88 /**
89  * start a hardware timer
90  *
91  * @return  0 == success, EIO == failure
92  */
duet_timer_start(duet_timer_dev_t * tim)93 int32_t duet_timer_start(duet_timer_dev_t *tim)
94 {
95     uint32_t reg_value;
96     if (NULL == tim) {
97         return EIO;
98     }
99     if (DUET_TIMER1_INDEX == tim->port) {
100         TIMER1->CONTROL |= (TIMER_ENABLE | INTERRUPT_EN); // timer control
101     } else if (DUET_TIMER2_INDEX == tim->port) {
102         TIMER2->CONTROL |= (TIMER_ENABLE | INTERRUPT_EN); // timer control
103     } else {
104         return EIO;
105     }
106     // open TIMER interrupt
107     reg_value = REG_RD(DUTE_IRQ_EN_REG) & (~TIMER_IRQ_BIT);
108     REG_WR(DUTE_IRQ_EN_REG, (reg_value | (TIMER_IRQ_BIT)));
109     NVIC_EnableIRQ(TIMER_IRQn); // 0x20
110     return 0;
111 }
112 
113 /**
114  * get hardware timer remain time
115  *
116  * @return   success return remain time, EIO == failure
117  */
duet_timer_get(duet_timer_dev_t * tim)118 int32_t duet_timer_get(duet_timer_dev_t *tim)
119 {
120     uint32_t reg_value = 0;
121     uint32_t system_clock = SYSTEM_CLOCK;
122 
123     if (NULL == tim) {
124         return -1;
125     }
126     if (DUET_TIMER1_INDEX == tim->port) {
127         reg_value = TIMER1->VALUE; // timer current value
128         return (reg_value / (system_clock / 1000000)); // time for us
129     } else if (DUET_TIMER2_INDEX == tim->port) {
130         reg_value = TIMER2->VALUE; // timer current value
131         return (reg_value / (system_clock / 1000000)); // time for us
132     } else {
133         return -1;
134     }
135     return 0;
136 }
137 
138 /**
139  * reload hardware timer value
140  *
141  * @return   0 == success, EIO == failure
142  */
duet_timer_reload(duet_timer_dev_t * tim)143 int32_t duet_timer_reload(duet_timer_dev_t *tim)
144 {
145     uint32_t system_clock = SYSTEM_CLOCK;
146 
147     if (NULL == tim) {
148         return -1;
149     }
150     if (tim->port >= DUET_TIMER_NUM) {
151         return -1;
152     }
153     if (DUET_TIMER1_INDEX == tim->port) {
154         TIMER1->LOAD = tim->config.period * (system_clock / 1000000); // 1000000 for us
155     } else { // if(DUET_TIMER2_INDEX == tim->port)
156         TIMER2->LOAD = tim->config.period * (system_clock / 1000000); // 1000000 for us
157     }
158     return 0;
159 }
160 
161 /**
162  * stop a hardware timer
163  *
164  * @param[in]  tmr  timer struct
165  * @param[in]  cb   callback to be triggered after useconds
166  * @param[in]  arg  passed to cb
167  */
duet_timer_stop(duet_timer_dev_t * tim)168 void duet_timer_stop(duet_timer_dev_t *tim)
169 {
170     if (NULL == tim) {
171         return;
172     }
173 
174     if (DUET_TIMER1_INDEX == tim->port) {
175         TIMER1->CONTROL = TIMER_DISABLE; // timer control
176     } else if (DUET_TIMER2_INDEX == tim->port) {
177         TIMER2->CONTROL = TIMER_DISABLE; // timer control
178     } else {
179         return;
180     }
181 
182     // two timers use same IRQ
183     // NVIC_DisableIRQ(TIMER_IRQn);
184     g_duet_timer_handler[tim->port].cb = NULL;
185     g_duet_timer_handler[tim->port].arg = NULL;
186 }
187 
188 /**
189  * De-initialises an TIMER interface, Turns off an TIMER hardware interface
190  *
191  * @param[in]  timer  the interface which should be de-initialised
192  *
193  * @return  0 : on success, EIO : if an error occurred with any step
194  */
duet_timer_finalize(duet_timer_dev_t * tim)195 int32_t duet_timer_finalize(duet_timer_dev_t *tim)
196 {
197     // uint32_t reg_value;
198     duet_timer_stop(tim);
199     // Set Timer Clock Disable
200     // one clk enable for 2 timer
201     // reg_value = REG_RD(PERI_CLK_DIS_REG1) & (~TIMER_BUS_CLK_BIT);
202     // REG_WR(PERI_CLK_DIS_REG1, (reg_value | (TIMER_BUS_CLK_BIT)));
203     return 0;
204 }
205