Когда должны срабатывать таймеры программного обеспечения по сравнению с их предыдущим таймаутом? - PullRequest
3 голосов
/ 24 марта 2011

Я думаю, что это один из тех вопросов типа "vi vs. emacs", но я все равно буду задавать, так как хотел бы услышать мнения людей.

Часто во встроенной системе микроконтроллер имеетпериферийное устройство аппаратного таймера, которое обеспечивает базу синхронизации для подсистемы программного таймера.Эта подсистема позволяет разработчику создавать произвольное (ограниченное системными ресурсами) количество таймеров, которые можно использовать для генерации и управления событиями в системе.Способ, которым программные таймеры обычно управляются, состоит в том, что аппаратный таймер настроен на генерацию с фиксированным интервалом (или иногда только тогда, когда истекает следующий активный таймер).В обработчике прерываний вызывается функция обратного вызова для выполнения действий, специфичных для этого таймера.Как всегда, эти подпрограммы обратного вызова должны быть очень короткими, поскольку они выполняются в контексте прерывания.

Допустим, я создаю таймер, который срабатывает каждые 1 мс, а его подпрограмме обратного вызова требуется 100 мсек для выполнения, и это единственноеИнтерес происходит в системе.Когда подсистема таймера должна планировать следующую обработку этого программного таймера?Должно ли это быть 1 мс от момента возникновения прерывания или 1 мс от момента завершения обратного вызова?

Чтобы сделать вещи более интересными, скажем, что разработчик оборудования приходит и говорит, что в определенных режимах работы требуется скорость ЦПдолжно быть уменьшено до 20% от максимального для экономии энергии.Теперь процедура обратного вызова занимает 500 мкс вместо 100 мкс, но интервал таймера по-прежнему составляет 1 мс.Предположим, что эта увеличенная задержка в обратном вызове не оказывает негативного влияния на систему в этом режиме ожидания.Опять же, когда подсистема таймера должна планировать следующую обработку этого программного времени?T + 1 мс или T + 500 мкс + 1 мс?

Или, возможно, в обоих случаях следует разделить разницу и запланировать ее на T + (execute_time / 2) + 1 мс?

Ответы [ 4 ]

5 голосов
/ 24 марта 2011

В ОС реального времени таймеры и задержки синхронизируются с системным тиком, поэтому, если обработка события занимает менее одного тика таймера и начинается на границе тика таймера, не будет никакой разницы в планировании между использованием таймераили задержка.

Если, с другой стороны, обработка заняла более одного такта, вам потребуется событие таймера, чтобы обеспечить детерминированную синхронизацию без дрожания.

В большинстве случаев детерминизм важен или важени делает поведение системы более предсказуемым.Если отсчет времени увеличивался с момента окончания обработки, изменчивость в обработке (статическая - с помощью изменений кода или во время выполнения с помощью разных путей выполнения) может привести к изменчивому поведению и непроверенным угловым случаям, которые трудно отладить или могут вызвать системнуюотказ.

3 голосов
/ 24 марта 2011

Я бы включил аппаратный таймер каждые 1 мс. Я никогда не слышал о аппаратном таймере, учитывающем такую ​​быструю рутину. Тем более, что вам придется пересчитывать каждый раз, когда происходит изменение программного обеспечения. Или выясните, что делать, когда процессор меняет тактовые частоты. Или подумайте, что делать, если вы решите обновить / понизить используемый процессор.

1 голос
/ 25 марта 2011

Добавление еще пары причин к тому, что на данный момент является согласованным ответом (таймер должен срабатывать каждые 1 мс):

  • Если таймер срабатывает каждые 1 мс, и то, что вы действительно хотитепромежуток между выполнениями составляет 1 мс, вы можете сбросить таймер на выходе из функции обратного вызова, чтобы с этой точки срабатывал 1 мс.

  • Однако, если таймер срабатывает через 1 мс после выхода из функции обратного вызоваи вам нужно другое поведение, вы как бы застряли.

Кроме того, в оборудовании гораздо менее сложно запускать каждые 1 мс.Чтобы сделать это, он просто генерирует события и сбрасывает, и нет обратной связи от программного обеспечения к таймеру, кроме как в точке установки.Если таймер оставляет интервалы в 1 мс, программное обеспечение должно каким-то образом сигнализировать таймеру о том, что оно завершает обратный вызов.

И вам, конечно, не следует «разделять разницу».Это делает неправильную вещь для каждого , и еще более неприятно обходиться, если кто-то хочет заставить его сделать что-то еще.

0 голосов
/ 28 марта 2011

Я склоняюсь к тому, чтобы поведение по умолчанию состояло в том, чтобы рутина запускалась с интервалами, которые почти одинаковы с практикой, и чтобы рутина, которая запаздывала, пыталась «догнать» в определенных пределах. Иногда хорошим шаблоном может быть что-то вроде:

/* Assume 32,768Hz interrupt, and that we want foo() to execute 1024x/second */

  typedef unsigned short ui; /* Use whatever size int works out best */
  ui current_ticks;  /* 32768Hz ticks */

  ui next_scheduled_event;
  ui next_event;

void interrupt_handler(void)
{
  current_ticks++;
  ...
  if ((ui)(current_ticks - next_event)  EVENT_INTERVAL*EVENT_MAX_BACKLOG)  /* We're 32 ticks behind -- don't even try to catch up */
    {
      delta = EVENT_INTERVAL*EVENT_MAX_BACKLOG;
      next_scheduled_event = current_ticks - delta;
    }
    next_scheduled_event += EVENT_INTERVAL;
    next_event = next_scheduled_event;

    foo();

    /* See how much time there is before the next event */
    delta = (ui)(current_ticks - next_event - EVENT_MIN_SPACING);
    if (delta > 32768)
      next_event = current_ticks + EVENT_MIN_GAP;
  }

Этот код (непроверенный) будет запускать foo () с одинаковой скоростью, если это возможно, но всегда будет разрешать EVENT_MIN_SPACING между выполнениями. Если он иногда не может работать с желаемой скоростью, он будет запускаться несколько раз с EVENT_MIN_SPACING между выполнениями, пока он не «догонит». Если он слишком сильно отстает, его попытки сыграть в догонялки будут ограничены.

...