Ignore:
Timestamp:
Apr 5, 2019, 9:26:53 PM (5 years ago)
Author:
coas-nagasima
Message:

mbed関連を更新
シリアルドライバをmbedのHALを使うよう変更
ファイルディスクリプタの処理を更新

File:
1 edited

Legend:

Unmodified
Added
Removed
  • asp3_tinet_ecnl_arm/trunk/asp3_dcre/mbed/hal/mbed_ticker_api.c

    r352 r374  
    1414 * limitations under the License.
    1515 */
     16#include <stdio.h>
    1617#include <stddef.h>
    1718#include "hal/ticker_api.h"
    1819#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
     22static void schedule_interrupt(const ticker_data_t *const ticker);
     23static void update_present_time(const ticker_data_t *const ticker);
     24
     25/*
     26 * Initialize a ticker instance.
     27 */
     28static 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 */
     86static 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 */
     110static 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 */
     125static 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 */
     177static 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 */
     215int _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 */
     237static 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
     278void 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
     287void 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    }
    28296
    29297    /* Go through all the pending TimerEvents */
     298    ticker->queue->dispatching = true;
    30299    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) {
    38308            // This event was in the past:
    39309            //      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 events
     310            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
    44314            }
    45315            /* Note: We continue back to examining the head because calling the
    46316             * event handler may have altered the chain of pending events. */
    47317        } 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
     328void 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
     348void 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);
    59354
    60355    // initialise our data
     
    65360       an element this should come before (which is possibly the
    66361       head). */
    67     ticker_event_t *prev = NULL, *p = data->queue->head;
     362    ticker_event_t *prev = NULL, *p = ticker->queue->head;
    68363    while (p != NULL) {
    69364        /* check if we come before p */
    70         if ((int)(timestamp - p->timestamp) < 0) {
     365        if (timestamp < p->timestamp) {
    71366            break;
    72367        }
     
    75370        p = p->next;
    76371    }
    77    
     372
    78373    /* if we're at the end p will be NULL, which is correct */
    79374    obj->next = p;
     
    81376    /* if prev is NULL we're at the head */
    82377    if (prev == NULL) {
    83         data->queue->head = obj;
    84         data->interface->set_interrupt(timestamp);
     378        ticker->queue->head = obj;
     379        schedule_interrupt(ticker);
    85380    } else {
    86381        prev->next = obj;
     
    90385}
    91386
    92 void ticker_remove_event(const ticker_data_t *const data, ticker_event_t *obj) {
     387void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj)
     388{
    93389    core_util_critical_section_enter();
    94390
    95391    // remove this object from the list
    96     if (data->queue->head == obj) {
     392    if (ticker->queue->head == obj) {
    97393        // 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);
    104396    } else {
    105397        // find the object before me, then drop me
    106         ticker_event_t* p = data->queue->head;
     398        ticker_event_t *p = ticker->queue->head;
    107399        while (p != NULL) {
    108400            if (p->next == obj) {
     
    117409}
    118410
    119 timestamp_t ticker_read(const ticker_data_t *const data)
    120 {
    121     return data->interface->read();
     411timestamp_t ticker_read(const ticker_data_t *const ticker)
     412{
     413    return ticker_read_us(ticker);
     414}
     415
     416us_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;
    122425}
    123426
     
    136439    return ret;
    137440}
     441
     442void 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
     451void 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.