Update to new build system.
[clinton/Smoothieware.git] / mbed / src / vendor / NXP / capi / us_ticker_api.c
1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2013 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 #include <stddef.h>
17 #include "us_ticker_api.h"
18 #include "PeripheralNames.h"
19
20 /* PORTING STEP 4:
21 Implement
22 * "us_ticker_init", "us_ticker_read"
23 * "us_ticker_set_interrupt", "us_ticker_disable_interrupt", "us_ticker_clear_interrupt"
24 */
25 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
26 #define US_TICKER_TIMER ((LPC_TIM_TypeDef *)LPC_TIM3_BASE)
27 #define US_TICKER_TIMER_IRQn TIMER3_IRQn
28
29 #elif defined(TARGET_LPC11U24)
30 #define US_TICKER_TIMER ((LPC_CTxxBx_Type *)LPC_CT32B1_BASE)
31 #define US_TICKER_TIMER_IRQn TIMER_32_1_IRQn
32
33 #endif
34
35 static int us_ticker_running = 0;
36
37 static inline void us_ticker_init(void) {
38 us_ticker_running = 1;
39 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
40 LPC_SC->PCONP |= 1 << 23; // Clock TIMER_3
41
42 US_TICKER_TIMER->CTCR = 0x0; // timer mode
43 uint32_t PCLK = SystemCoreClock / 4;
44
45 #elif defined(TARGET_LPC11U24)
46 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<10); // Clock TIMER_1
47 uint32_t PCLK = SystemCoreClock;
48
49 #endif
50 US_TICKER_TIMER->TCR = 0x2; // reset
51
52 uint32_t prescale = PCLK / 1000000; // default to 1MHz (1 us ticks)
53 US_TICKER_TIMER->PR = prescale - 1;
54 US_TICKER_TIMER->TCR = 1; // enable = 1, reset = 0
55 }
56
57 uint32_t us_ticker_read() {
58 if (!us_ticker_running)
59 us_ticker_init();
60
61 return US_TICKER_TIMER->TC;
62 }
63
64 static inline void us_ticker_set_interrupt(unsigned int timestamp) {
65 // set match value
66 US_TICKER_TIMER->MR0 = timestamp;
67 // enable match interrupt
68 US_TICKER_TIMER->MCR |= 1;
69 }
70
71 static inline void us_ticker_disable_interrupt(void) {
72 US_TICKER_TIMER->MCR &= ~1;
73 }
74
75 static inline void us_ticker_clear_interrupt(void) {
76 US_TICKER_TIMER->IR = 1;
77 }
78
79 static ticker_event_handler event_handler;
80 static ticker_event_t *head = NULL;
81
82 void irq_handler(void) {
83 us_ticker_clear_interrupt();
84
85 /* Go through all the pending TimerEvents */
86 while (1) {
87 if (head == NULL) {
88 // There are no more TimerEvents left, so disable matches.
89 us_ticker_disable_interrupt();
90 return;
91 }
92
93 if ((int)(head->timestamp - us_ticker_read()) <= 0) {
94 // This event was in the past:
95 // point to the following one and execute its handler
96 ticker_event_t *p = head;
97 head = head->next;
98
99 event_handler(p->id); // NOTE: the handler can set new events
100
101 } else {
102 // This event and the following ones in the list are in the future:
103 // set it as next interrupt and return
104 us_ticker_set_interrupt(head->timestamp);
105 return;
106 }
107 }
108 }
109
110 void us_ticker_set_handler(ticker_event_handler handler) {
111 event_handler = handler;
112
113 NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)irq_handler);
114 NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
115 }
116
117 void us_ticker_insert_event(ticker_event_t *obj, unsigned int timestamp, uint32_t id) {
118 /* disable interrupts for the duration of the function */
119 __disable_irq();
120
121 // initialise our data
122 obj->timestamp = timestamp;
123 obj->id = id;
124
125 /* Go through the list until we either reach the end, or find
126 an element this should come before (which is possibly the
127 head). */
128 ticker_event_t *prev = NULL, *p = head;
129 while (p != NULL) {
130 /* check if we come before p */
131 if ((int)(timestamp - p->timestamp) <= 0) {
132 break;
133 }
134 /* go to the next element */
135 prev = p;
136 p = p->next;
137 }
138 /* if prev is NULL we're at the head */
139 if (prev == NULL) {
140 head = obj;
141 us_ticker_set_interrupt(timestamp);
142 } else {
143 prev->next = obj;
144 }
145 /* if we're at the end p will be NULL, which is correct */
146 obj->next = p;
147
148 __enable_irq();
149 }
150
151 void us_ticker_remove_event(ticker_event_t *obj) {
152 __disable_irq();
153
154 // remove this object from the list
155 if (head == obj) { // first in the list, so just drop me
156 head = obj->next;
157 if (obj->next != NULL) {
158 us_ticker_set_interrupt(head->timestamp);
159 }
160 } else { // find the object before me, then drop me
161 ticker_event_t* p = head;
162 while (p != NULL) {
163 if (p->next == obj) {
164 p->next = obj->next;
165 break;
166 }
167 p = p->next;
168 }
169 }
170
171 __enable_irq();
172 }