mbed library sources. Supersedes mbed-src. Fixed broken STM32F1xx RTC on rtc_api.c
Dependents: Nucleo_F103RB_RTC_battery_bkup_pwr_off_okay
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 Thu Jul 14 2022 19:34:39 by 1.7.2