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 official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_ticker_api.c Source File

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 }