1 /**
2 * \file
3 *
4 * \brief Timer functionality implementation.
5 *
6 * Copyright (C) 2014 - 2016 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43
44 #include "sw_timer.h"
45 #include <utils_assert.h>
46 #include <utils.h>
47 #include <hal_atomic.h>
48 #include <hpl_irq.h>
49 #include "atmel_start_pins.h"
50 /**
51 * \brief Driver version
52 */
53 #define DRIVER_VERSION 0x00000001u
54
55 /**
56 * \brief Timer flags
57 */
58 #define TIMER_FLAG_QUEUE_IS_TAKEN 1
59 #define TIMER_FLAG_INTERRUPT_TRIGERRED 2
60
61 static void timer_add_timer_task(struct list_descriptor *list, struct timer_task *const new_task, const uint32_t time);
62 static void timer_process_counted(struct _timer_device *device);
63
64 /**
65 * \brief Initialize timer
66 */
timer_init(struct timer_descriptor * const descr,void * const hw,struct _timer_hpl_interface * const func)67 int32_t timer_init(struct timer_descriptor *const descr, void *const hw, struct _timer_hpl_interface *const func)
68 {
69 ASSERT(descr && hw);
70 _timer_init(&descr->device, hw);
71 descr->time = 0;
72 descr->device.timer_cb.period_expired = timer_process_counted;
73
74 return ERR_NONE;
75 }
76
77 /**
78 * \brief Deinitialize timer
79 */
timer_deinit(struct timer_descriptor * const descr)80 int32_t timer_deinit(struct timer_descriptor *const descr)
81 {
82 ASSERT(descr);
83 _timer_deinit(&descr->device);
84
85 return ERR_NONE;
86 }
87
88 /**
89 * \brief Start timer
90 */
timer_start(struct timer_descriptor * const descr)91 int32_t timer_start(struct timer_descriptor *const descr)
92 {
93 ASSERT(descr);
94 if (_timer_is_started(&descr->device)) {
95 return ERR_DENIED;
96 }
97 _timer_start(&descr->device);
98
99 return ERR_NONE;
100 }
101
102 /**
103 * \brief Stop timer
104 */
timer_stop(struct timer_descriptor * const descr)105 int32_t timer_stop(struct timer_descriptor *const descr)
106 {
107 ASSERT(descr);
108 if (!_timer_is_started(&descr->device)) {
109 return ERR_DENIED;
110 }
111 _timer_stop(&descr->device);
112
113 return ERR_NONE;
114 }
115
116 /**
117 * \brief Set amount of clock cycler per timer tick
118 */
timer_set_clock_cycles_per_tick(struct timer_descriptor * const descr,const uint32_t clock_cycles)119 int32_t timer_set_clock_cycles_per_tick(struct timer_descriptor *const descr, const uint32_t clock_cycles)
120 {
121 ASSERT(descr);
122 _timer_set_period(&descr->device, clock_cycles);
123
124 return ERR_NONE;
125 }
126
127 /**
128 * \brief Add timer task
129 */
timer_add_task(struct timer_descriptor * const descr,struct timer_task * const task)130 int32_t timer_add_task(struct timer_descriptor *const descr, struct timer_task *const task)
131 {
132 ASSERT(descr && task);
133
134 descr->flags |= TIMER_FLAG_QUEUE_IS_TAKEN;
135 if (is_list_element(&descr->tasks, task)) {
136 descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN;
137 ASSERT(false);
138 return ERR_ALREADY_INITIALIZED;
139 }
140 task->time_label = descr->time;
141 timer_add_timer_task(&descr->tasks, task, descr->time);
142
143 descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN;
144 if (descr->flags & TIMER_FLAG_INTERRUPT_TRIGERRED) {
145 CRITICAL_SECTION_ENTER()
146 descr->flags &= ~TIMER_FLAG_INTERRUPT_TRIGERRED;
147 _timer_set_irq(&descr->device);
148 CRITICAL_SECTION_LEAVE()
149 }
150
151 return ERR_NONE;
152 }
153
154 /**
155 * \brief Remove timer task
156 */
timer_remove_task(struct timer_descriptor * const descr,const struct timer_task * const task)157 int32_t timer_remove_task(struct timer_descriptor *const descr, const struct timer_task *const task)
158 {
159 ASSERT(descr && task);
160
161 descr->flags |= TIMER_FLAG_QUEUE_IS_TAKEN;
162 if (!is_list_element(&descr->tasks, task)) {
163 descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN;
164 ASSERT(false);
165 return ERR_NOT_FOUND;
166 }
167 list_delete_element(&descr->tasks, task);
168
169 descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN;
170 if (descr->flags & TIMER_FLAG_INTERRUPT_TRIGERRED) {
171 CRITICAL_SECTION_ENTER()
172 descr->flags &= ~TIMER_FLAG_INTERRUPT_TRIGERRED;
173 _timer_set_irq(&descr->device);
174 CRITICAL_SECTION_LEAVE()
175 }
176
177 return ERR_NONE;
178 }
179
180 /**
181 * \brief Retrieve the amount of clock cycles in a tick
182 */
timer_get_clock_cycles_in_tick(const struct timer_descriptor * const descr,uint32_t * const cycles)183 int32_t timer_get_clock_cycles_in_tick(const struct timer_descriptor *const descr, uint32_t *const cycles)
184 {
185 ASSERT(descr && cycles);
186 *cycles = _timer_get_period(&descr->device);
187 return ERR_NONE;
188 }
189
190 /**
191 * \brief Retrieve the current driver version
192 */
timer_get_version(void)193 uint32_t timer_get_version(void)
194 {
195 return DRIVER_VERSION;
196 }
197
198 /**
199 * \internal Insert a timer task into sorted timer's list
200 *
201 * \param[in] head The pointer to the head of timer task list
202 * \param[in] task The pointer to task to add
203 * \param[in] time Current timer time
204 */
timer_add_timer_task(struct list_descriptor * list,struct timer_task * const new_task,const uint32_t time)205 static void timer_add_timer_task(struct list_descriptor *list, struct timer_task *const new_task, const uint32_t time)
206 {
207 struct timer_task *it, *prev = NULL, *head = (struct timer_task *)list_get_head(list);
208
209 if (!head) {
210 list_insert_as_head(list, new_task);
211 return;
212 }
213
214 for (it = head; it; it = (struct timer_task *)list_get_next_element(it)) {
215 uint32_t time_left;
216
217 if (it->time_label <= time) {
218 time_left = it->interval - (time - it->time_label);
219 } else {
220 time_left = it->interval - (0xFFFFFFFF - it->time_label) - time;
221 }
222 if (time_left >= new_task->interval)
223 break;
224 prev = it;
225 }
226
227 if (it == head) {
228 list_insert_as_head(list, new_task);
229 } else {
230 list_insert_after(prev, new_task);
231 }
232 }
233
234 /**
235 * \internal Process interrupts
236 */
timer_process_counted(struct _timer_device * device)237 static void timer_process_counted(struct _timer_device *device)
238 {
239 struct timer_descriptor *timer = CONTAINER_OF(device, struct timer_descriptor, device);
240 struct timer_task * it = (struct timer_task *)list_get_head(&timer->tasks);
241 uint32_t time = ++timer->time;
242 gpio_toggle_pin_level(PA15);
243 if ((timer->flags & TIMER_FLAG_QUEUE_IS_TAKEN) || (timer->flags & TIMER_FLAG_INTERRUPT_TRIGERRED)) {
244 timer->flags |= TIMER_FLAG_INTERRUPT_TRIGERRED;
245 return;
246 }
247
248 while (it && ((time - it->time_label) >= it->interval)) {
249 struct timer_task *tmp = it;
250
251 list_remove_head(&timer->tasks);
252 if (TIMER_TASK_REPEAT == tmp->mode) {
253 tmp->time_label = time;
254 timer_add_timer_task(&timer->tasks, tmp, time);
255 }
256 it = (struct timer_task *)list_get_head(&timer->tasks);
257
258 tmp->cb(tmp);
259 }
260 }
261