- Timestamp:
- Apr 5, 2019, 9:26:53 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
asp3_tinet_ecnl_arm/trunk/asp3_dcre/mbed/hal/mbed_ticker_api.c
r352 r374 14 14 * limitations under the License. 15 15 */ 16 #include <stdio.h> 16 17 #include <stddef.h> 17 18 #include "hal/ticker_api.h" 18 19 #include "platform/mbed_critical.h" 19 20 void ticker_set_handler(const ticker_data_t *const data, ticker_event_handler handler) { 21 data->interface->init(); 22 23 data->queue->event_handler = handler; 24 } 25 26 void ticker_irq_handler(const ticker_data_t *const data) { 27 data->interface->clear_interrupt(); 20 #include "platform/mbed_assert.h" 21 22 static void schedule_interrupt(const ticker_data_t *const ticker); 23 static void update_present_time(const ticker_data_t *const ticker); 24 25 /* 26 * Initialize a ticker instance. 27 */ 28 static void initialize(const ticker_data_t *ticker) 29 { 30 // return if the queue has already been initialized, in that case the 31 // interface used by the queue is already initialized. 32 if (ticker->queue->initialized) { 33 return; 34 } 35 if (ticker->queue->suspended) { 36 return; 37 } 38 39 ticker->interface->init(); 40 41 const ticker_info_t *info = ticker->interface->get_info(); 42 uint32_t frequency = info->frequency; 43 if (info->frequency == 0) { 44 MBED_ASSERT(0); 45 frequency = 1000000; 46 } 47 48 uint8_t frequency_shifts = 0; 49 for (uint8_t i = 31; i > 0; --i) { 50 if ((1 << i) == frequency) { 51 frequency_shifts = i; 52 break; 53 } 54 } 55 56 uint32_t bits = info->bits; 57 if ((info->bits > 32) || (info->bits < 4)) { 58 MBED_ASSERT(0); 59 bits = 32; 60 } 61 uint32_t max_delta = 0x7 << (bits - 4); // 7/16th 62 uint64_t max_delta_us = 63 ((uint64_t)max_delta * 1000000 + frequency - 1) / frequency; 64 65 ticker->queue->event_handler = NULL; 66 ticker->queue->head = NULL; 67 ticker->queue->tick_last_read = ticker->interface->read(); 68 ticker->queue->tick_remainder = 0; 69 ticker->queue->frequency = frequency; 70 ticker->queue->frequency_shifts = frequency_shifts; 71 ticker->queue->bitmask = ((uint64_t)1 << bits) - 1; 72 ticker->queue->max_delta = max_delta; 73 ticker->queue->max_delta_us = max_delta_us; 74 ticker->queue->present_time = 0; 75 ticker->queue->dispatching = false; 76 ticker->queue->suspended = false; 77 ticker->queue->initialized = true; 78 79 update_present_time(ticker); 80 schedule_interrupt(ticker); 81 } 82 83 /** 84 * Set the event handler function of a ticker instance. 85 */ 86 static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) 87 { 88 ticker->queue->event_handler = handler; 89 } 90 91 /* 92 * Convert a 32 bit timestamp into a 64 bit timestamp. 93 * 94 * A 64 bit timestamp is used as the point of time of reference while the 95 * timestamp to convert is relative to this point of time. 96 * 97 * The lower 32 bits of the timestamp returned will be equal to the timestamp to 98 * convert. 99 * 100 * If the timestamp to convert is less than the lower 32 bits of the time 101 * reference then the timestamp to convert is seen as an overflowed value and 102 * the upper 32 bit of the timestamp returned will be equal to the upper 32 bit 103 * of the reference point + 1. 104 * Otherwise, the upper 32 bit returned will be equal to the upper 32 bit of the 105 * reference point. 106 * 107 * @param ref: The 64 bit timestamp of reference. 108 * @param timestamp: The timestamp to convert. 109 */ 110 static us_timestamp_t convert_timestamp(us_timestamp_t ref, timestamp_t timestamp) 111 { 112 bool overflow = timestamp < ((timestamp_t) ref) ? true : false; 113 114 us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | timestamp; 115 if (overflow) { 116 result += (1ULL << 32); 117 } 118 119 return result; 120 } 121 122 /** 123 * Update the present timestamp value of a ticker. 124 */ 125 static void update_present_time(const ticker_data_t *const ticker) 126 { 127 ticker_event_queue_t *queue = ticker->queue; 128 if (queue->suspended) { 129 return; 130 } 131 uint32_t ticker_time = ticker->interface->read(); 132 if (ticker_time == ticker->queue->tick_last_read) { 133 // No work to do 134 return; 135 } 136 137 uint64_t elapsed_ticks = (ticker_time - queue->tick_last_read) & queue->bitmask; 138 queue->tick_last_read = ticker_time; 139 140 uint64_t elapsed_us; 141 if (1000000 == queue->frequency) { 142 // Optimized for 1MHz 143 144 elapsed_us = elapsed_ticks; 145 } else if (0 != queue->frequency_shifts) { 146 // Optimized for frequencies divisible by 2 147 uint64_t us_x_ticks = elapsed_ticks * 1000000; 148 elapsed_us = us_x_ticks >> queue->frequency_shifts; 149 150 // Update remainder 151 queue->tick_remainder += us_x_ticks - (elapsed_us << queue->frequency_shifts); 152 if (queue->tick_remainder >= queue->frequency) { 153 elapsed_us += 1; 154 queue->tick_remainder -= queue->frequency; 155 } 156 } else { 157 // General case 158 159 uint64_t us_x_ticks = elapsed_ticks * 1000000; 160 elapsed_us = us_x_ticks / queue->frequency; 161 162 // Update remainder 163 queue->tick_remainder += us_x_ticks - elapsed_us * queue->frequency; 164 if (queue->tick_remainder >= queue->frequency) { 165 elapsed_us += 1; 166 queue->tick_remainder -= queue->frequency; 167 } 168 } 169 170 // Update current time 171 queue->present_time += elapsed_us; 172 } 173 174 /** 175 * Given the absolute timestamp compute the hal tick timestamp rounded up. 176 */ 177 static timestamp_t compute_tick_round_up(const ticker_data_t *const ticker, us_timestamp_t timestamp) 178 { 179 ticker_event_queue_t *queue = ticker->queue; 180 us_timestamp_t delta_us = timestamp - queue->present_time; 181 182 timestamp_t delta = ticker->queue->max_delta; 183 if (delta_us <= ticker->queue->max_delta_us) { 184 // Checking max_delta_us ensures the operation will not overflow 185 186 if (1000000 == queue->frequency) { 187 // Optimized for 1MHz 188 189 delta = delta_us; 190 if (delta > ticker->queue->max_delta) { 191 delta = ticker->queue->max_delta; 192 } 193 } else if (0 != queue->frequency_shifts) { 194 // Optimized frequencies divisible by 2 195 196 delta = ((delta_us << ticker->queue->frequency_shifts) + 1000000 - 1) / 1000000; 197 if (delta > ticker->queue->max_delta) { 198 delta = ticker->queue->max_delta; 199 } 200 } else { 201 // General case 202 203 delta = (delta_us * queue->frequency + 1000000 - 1) / 1000000; 204 if (delta > ticker->queue->max_delta) { 205 delta = ticker->queue->max_delta; 206 } 207 } 208 } 209 return (queue->tick_last_read + delta) & queue->bitmask; 210 } 211 212 /** 213 * Return 1 if the tick has incremented to or past match_tick, otherwise 0. 214 */ 215 int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick) 216 { 217 if (match_tick > prev_tick) { 218 return (cur_tick >= match_tick) || (cur_tick < prev_tick); 219 } else { 220 return (cur_tick < prev_tick) && (cur_tick >= match_tick); 221 } 222 } 223 224 /** 225 * Compute the time when the interrupt has to be triggered and schedule it. 226 * 227 * If there is no event in the queue or the next event to execute is in more 228 * than ticker.queue.max_delta ticks from now then the ticker irq will be 229 * scheduled in ticker.queue.max_delta ticks. Otherwise the irq will be 230 * scheduled to happen when the running counter reach the timestamp of the 231 * first event in the queue. 232 * 233 * @note If there is no event in the queue then the interrupt is scheduled to 234 * in ticker.queue.max_delta. This is necessary to keep track 235 * of the timer overflow. 236 */ 237 static void schedule_interrupt(const ticker_data_t *const ticker) 238 { 239 ticker_event_queue_t *queue = ticker->queue; 240 if (queue->suspended || ticker->queue->dispatching) { 241 // Don't schedule the next interrupt until dispatching is 242 // finished. This prevents repeated calls to interface->set_interrupt 243 return; 244 } 245 246 update_present_time(ticker); 247 248 if (ticker->queue->head) { 249 us_timestamp_t present = ticker->queue->present_time; 250 us_timestamp_t match_time = ticker->queue->head->timestamp; 251 252 // if the event at the head of the queue is in the past then schedule 253 // it immediately. 254 if (match_time <= present) { 255 ticker->interface->fire_interrupt(); 256 return; 257 } 258 259 timestamp_t match_tick = compute_tick_round_up(ticker, match_time); 260 261 // The same tick should never occur since match_tick is rounded up. 262 // If the same tick is returned scheduling will not work correctly. 263 MBED_ASSERT(match_tick != queue->tick_last_read); 264 265 ticker->interface->set_interrupt(match_tick); 266 timestamp_t cur_tick = ticker->interface->read(); 267 268 if (_ticker_match_interval_passed(queue->tick_last_read, cur_tick, match_tick)) { 269 ticker->interface->fire_interrupt(); 270 } 271 } else { 272 uint32_t match_tick = 273 (queue->tick_last_read + queue->max_delta) & queue->bitmask; 274 ticker->interface->set_interrupt(match_tick); 275 } 276 } 277 278 void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) 279 { 280 initialize(ticker); 281 282 core_util_critical_section_enter(); 283 set_handler(ticker, handler); 284 core_util_critical_section_exit(); 285 } 286 287 void ticker_irq_handler(const ticker_data_t *const ticker) 288 { 289 core_util_critical_section_enter(); 290 291 ticker->interface->clear_interrupt(); 292 if (ticker->queue->suspended) { 293 core_util_critical_section_exit(); 294 return; 295 } 28 296 29 297 /* Go through all the pending TimerEvents */ 298 ticker->queue->dispatching = true; 30 299 while (1) { 31 if (data->queue->head == NULL) { 32 // There are no more TimerEvents left, so disable matches. 33 data->interface->disable_interrupt(); 34 return; 35 } 36 37 if ((int)(data->queue->head->timestamp - data->interface->read()) <= 0) { 300 if (ticker->queue->head == NULL) { 301 break; 302 } 303 304 // update the current timestamp used by the queue 305 update_present_time(ticker); 306 307 if (ticker->queue->head->timestamp <= ticker->queue->present_time) { 38 308 // This event was in the past: 39 309 // point to the following one and execute its handler 40 ticker_event_t *p = data->queue->head;41 data->queue->head = data->queue->head->next;42 if ( data->queue->event_handler != NULL) {43 (* data->queue->event_handler)(p->id); // NOTE: the handler can set new events310 ticker_event_t *p = ticker->queue->head; 311 ticker->queue->head = ticker->queue->head->next; 312 if (ticker->queue->event_handler != NULL) { 313 (*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events 44 314 } 45 315 /* Note: We continue back to examining the head because calling the 46 316 * event handler may have altered the chain of pending events. */ 47 317 } else { 48 // This event and the following ones in the list are in the future: 49 // set it as next interrupt and return 50 data->interface->set_interrupt(data->queue->head->timestamp); 51 return; 52 } 53 } 54 } 55 56 void ticker_insert_event(const ticker_data_t *const data, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) { 57 /* disable interrupts for the duration of the function */ 58 core_util_critical_section_enter(); 318 break; 319 } 320 } 321 ticker->queue->dispatching = false; 322 323 schedule_interrupt(ticker); 324 325 core_util_critical_section_exit(); 326 } 327 328 void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) 329 { 330 core_util_critical_section_enter(); 331 332 // update the current timestamp 333 update_present_time(ticker); 334 us_timestamp_t absolute_timestamp = convert_timestamp( 335 ticker->queue->present_time, 336 timestamp 337 ); 338 339 // defer to ticker_insert_event_us 340 ticker_insert_event_us( 341 ticker, 342 obj, absolute_timestamp, id 343 ); 344 345 core_util_critical_section_exit(); 346 } 347 348 void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) 349 { 350 core_util_critical_section_enter(); 351 352 // update the current timestamp 353 update_present_time(ticker); 59 354 60 355 // initialise our data … … 65 360 an element this should come before (which is possibly the 66 361 head). */ 67 ticker_event_t *prev = NULL, *p = data->queue->head;362 ticker_event_t *prev = NULL, *p = ticker->queue->head; 68 363 while (p != NULL) { 69 364 /* check if we come before p */ 70 if ( (int)(timestamp - p->timestamp) < 0) {365 if (timestamp < p->timestamp) { 71 366 break; 72 367 } … … 75 370 p = p->next; 76 371 } 77 372 78 373 /* if we're at the end p will be NULL, which is correct */ 79 374 obj->next = p; … … 81 376 /* if prev is NULL we're at the head */ 82 377 if (prev == NULL) { 83 data->queue->head = obj;84 data->interface->set_interrupt(timestamp);378 ticker->queue->head = obj; 379 schedule_interrupt(ticker); 85 380 } else { 86 381 prev->next = obj; … … 90 385 } 91 386 92 void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) { 387 void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) 388 { 93 389 core_util_critical_section_enter(); 94 390 95 391 // remove this object from the list 96 if ( data->queue->head == obj) {392 if (ticker->queue->head == obj) { 97 393 // first in the list, so just drop me 98 data->queue->head = obj->next; 99 if (data->queue->head == NULL) { 100 data->interface->disable_interrupt(); 101 } else { 102 data->interface->set_interrupt(data->queue->head->timestamp); 103 } 394 ticker->queue->head = obj->next; 395 schedule_interrupt(ticker); 104 396 } else { 105 397 // find the object before me, then drop me 106 ticker_event_t * p = data->queue->head;398 ticker_event_t *p = ticker->queue->head; 107 399 while (p != NULL) { 108 400 if (p->next == obj) { … … 117 409 } 118 410 119 timestamp_t ticker_read(const ticker_data_t *const data) 120 { 121 return data->interface->read(); 411 timestamp_t ticker_read(const ticker_data_t *const ticker) 412 { 413 return ticker_read_us(ticker); 414 } 415 416 us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) 417 { 418 initialize(ticker); 419 420 core_util_critical_section_enter(); 421 update_present_time(ticker); 422 core_util_critical_section_exit(); 423 424 return ticker->queue->present_time; 122 425 } 123 426 … … 136 439 return ret; 137 440 } 441 442 void ticker_suspend(const ticker_data_t *const ticker) 443 { 444 core_util_critical_section_enter(); 445 446 ticker->queue->suspended = true; 447 448 core_util_critical_section_exit(); 449 } 450 451 void ticker_resume(const ticker_data_t *const ticker) 452 { 453 core_util_critical_section_enter(); 454 455 ticker->queue->suspended = false; 456 if (ticker->queue->initialized) { 457 ticker->queue->tick_last_read = ticker->interface->read(); 458 459 update_present_time(ticker); 460 schedule_interrupt(ticker); 461 } else { 462 initialize(ticker); 463 } 464 465 core_util_critical_section_exit(); 466 }
Note:
See TracChangeset
for help on using the changeset viewer.