Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
mbed_ticker_api.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2015 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include <stdio.h> 00017 #include <stddef.h> 00018 #include "hal/ticker_api.h" 00019 #include "platform/mbed_critical.h" 00020 00021 static void schedule_interrupt(const ticker_data_t *const ticker); 00022 static void update_present_time(const ticker_data_t *const ticker); 00023 00024 /* 00025 * Initialize a ticker instance. 00026 */ 00027 static void initialize(const ticker_data_t *ticker) 00028 { 00029 // return if the queue has already been initialized, in that case the 00030 // interface used by the queue is already initialized. 00031 if (ticker->queue->initialized) { 00032 return; 00033 } 00034 00035 ticker->interface->init(); 00036 00037 ticker->queue->event_handler = NULL; 00038 ticker->queue->head = NULL; 00039 ticker->queue->present_time = 0; 00040 ticker->queue->initialized = true; 00041 00042 update_present_time(ticker); 00043 schedule_interrupt(ticker); 00044 } 00045 00046 /** 00047 * Set the event handler function of a ticker instance. 00048 */ 00049 static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) 00050 { 00051 ticker->queue->event_handler = handler; 00052 } 00053 00054 /* 00055 * Convert a 32 bit timestamp into a 64 bit timestamp. 00056 * 00057 * A 64 bit timestamp is used as the point of time of reference while the 00058 * timestamp to convert is relative to this point of time. 00059 * 00060 * The lower 32 bits of the timestamp returned will be equal to the timestamp to 00061 * convert. 00062 * 00063 * If the timestamp to convert is less than the lower 32 bits of the time 00064 * reference then the timestamp to convert is seen as an overflowed value and 00065 * the upper 32 bit of the timestamp returned will be equal to the upper 32 bit 00066 * of the reference point + 1. 00067 * Otherwise, the upper 32 bit returned will be equal to the upper 32 bit of the 00068 * reference point. 00069 * 00070 * @param ref: The 64 bit timestamp of reference. 00071 * @param timestamp: The timestamp to convert. 00072 */ 00073 static us_timestamp_t convert_timestamp(us_timestamp_t ref, timestamp_t timestamp) 00074 { 00075 bool overflow = timestamp < ((timestamp_t) ref) ? true : false; 00076 00077 us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | timestamp; 00078 if (overflow) { 00079 result += (1ULL<<32); 00080 } 00081 00082 return result; 00083 } 00084 00085 /** 00086 * Update the present timestamp value of a ticker. 00087 */ 00088 static void update_present_time(const ticker_data_t *const ticker) 00089 { 00090 ticker->queue->present_time = convert_timestamp( 00091 ticker->queue->present_time, 00092 ticker->interface->read() 00093 ); 00094 } 00095 00096 /** 00097 * Compute the time when the interrupt has to be triggered and schedule it. 00098 * 00099 * If there is no event in the queue or the next event to execute is in more 00100 * than MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now then the ticker 00101 * irq will be scheduled in MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us. 00102 * Otherwise the irq will be scheduled to happen when the running counter reach 00103 * the timestamp of the first event in the queue. 00104 * 00105 * @note If there is no event in the queue then the interrupt is scheduled to 00106 * in MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA. This is necessary to keep track 00107 * of the timer overflow. 00108 */ 00109 static void schedule_interrupt(const ticker_data_t *const ticker) 00110 { 00111 update_present_time(ticker); 00112 uint32_t relative_timeout = MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA; 00113 00114 if (ticker->queue->head) { 00115 us_timestamp_t present = ticker->queue->present_time; 00116 us_timestamp_t next_event_timestamp = ticker->queue->head->timestamp; 00117 00118 // if the event at the head of the queue is in the past then schedule 00119 // it immediately. 00120 if (next_event_timestamp <= present) { 00121 ticker->interface->fire_interrupt(); 00122 return; 00123 } else if ((next_event_timestamp - present) < MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA) { 00124 relative_timeout = next_event_timestamp - present; 00125 } 00126 } 00127 00128 us_timestamp_t new_match_time = ticker->queue->present_time + relative_timeout; 00129 ticker->interface->set_interrupt(new_match_time); 00130 // there could be a delay, reread the time, check if it was set in the past 00131 // As result, if it is already in the past, we fire it immediately 00132 update_present_time(ticker); 00133 us_timestamp_t present = ticker->queue->present_time; 00134 if (present >= new_match_time) { 00135 ticker->interface->fire_interrupt(); 00136 } 00137 } 00138 00139 void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) 00140 { 00141 initialize(ticker); 00142 set_handler(ticker, handler); 00143 } 00144 00145 void ticker_irq_handler(const ticker_data_t *const ticker) 00146 { 00147 ticker->interface->clear_interrupt(); 00148 00149 /* Go through all the pending TimerEvents */ 00150 while (1) { 00151 if (ticker->queue->head == NULL) { 00152 break; 00153 } 00154 00155 // update the current timestamp used by the queue 00156 update_present_time(ticker); 00157 00158 if (ticker->queue->head->timestamp <= ticker->queue->present_time) { 00159 // This event was in the past: 00160 // point to the following one and execute its handler 00161 ticker_event_t *p = ticker->queue->head; 00162 ticker->queue->head = ticker->queue->head->next; 00163 if (ticker->queue->event_handler != NULL) { 00164 (*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events 00165 } 00166 /* Note: We continue back to examining the head because calling the 00167 * event handler may have altered the chain of pending events. */ 00168 } else { 00169 break; 00170 } 00171 } 00172 00173 schedule_interrupt(ticker); 00174 } 00175 00176 void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) 00177 { 00178 core_util_critical_section_enter(); 00179 00180 // update the current timestamp 00181 update_present_time(ticker); 00182 us_timestamp_t absolute_timestamp = convert_timestamp( 00183 ticker->queue->present_time, 00184 timestamp 00185 ); 00186 core_util_critical_section_exit(); 00187 00188 // defer to ticker_insert_event_us 00189 ticker_insert_event_us( 00190 ticker, 00191 obj, absolute_timestamp, id 00192 ); 00193 } 00194 00195 void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) 00196 { 00197 core_util_critical_section_enter(); 00198 00199 // update the current timestamp 00200 update_present_time(ticker); 00201 00202 // initialise our data 00203 obj->timestamp = timestamp; 00204 obj->id = id; 00205 00206 /* Go through the list until we either reach the end, or find 00207 an element this should come before (which is possibly the 00208 head). */ 00209 ticker_event_t *prev = NULL, *p = ticker->queue->head; 00210 while (p != NULL) { 00211 /* check if we come before p */ 00212 if (timestamp < p->timestamp) { 00213 break; 00214 } 00215 /* go to the next element */ 00216 prev = p; 00217 p = p->next; 00218 } 00219 00220 /* if we're at the end p will be NULL, which is correct */ 00221 obj->next = p; 00222 00223 /* if prev is NULL we're at the head */ 00224 if (prev == NULL) { 00225 ticker->queue->head = obj; 00226 } else { 00227 prev->next = obj; 00228 } 00229 00230 schedule_interrupt(ticker); 00231 00232 core_util_critical_section_exit(); 00233 } 00234 00235 void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) 00236 { 00237 core_util_critical_section_enter(); 00238 00239 // remove this object from the list 00240 if (ticker->queue->head == obj) { 00241 // first in the list, so just drop me 00242 ticker->queue->head = obj->next; 00243 schedule_interrupt(ticker); 00244 } else { 00245 // find the object before me, then drop me 00246 ticker_event_t* p = ticker->queue->head; 00247 while (p != NULL) { 00248 if (p->next == obj) { 00249 p->next = obj->next; 00250 break; 00251 } 00252 p = p->next; 00253 } 00254 } 00255 00256 core_util_critical_section_exit(); 00257 } 00258 00259 timestamp_t ticker_read(const ticker_data_t *const ticker) 00260 { 00261 return ticker_read_us(ticker); 00262 } 00263 00264 us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) 00265 { 00266 initialize(ticker); 00267 update_present_time(ticker); 00268 return ticker->queue->present_time; 00269 } 00270 00271 int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp) 00272 { 00273 int ret = 0; 00274 00275 /* if head is NULL, there are no pending events */ 00276 core_util_critical_section_enter(); 00277 if (data->queue->head != NULL) { 00278 *timestamp = data->queue->head->timestamp; 00279 ret = 1; 00280 } 00281 core_util_critical_section_exit(); 00282 00283 return ret; 00284 }
Generated on Wed Jul 27 2022 09:32:04 by
