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