Таймер с высоким разрешением

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Таймер с высоким разрешением

Сообщение shyub » 25.09.2016 12:05:59

Необходимо получать затержки порядка 10 микросекунд (упрвление шаговым двигателем). Задачу решил так: при запуске программы создаю и запускаю мультимедийный таймер, запускаю цикл записи в порт. По сработке таймера определяю количество выполненных записей, делю и затем использую полученный результат в отдельном потоке управления портом. Особо высокая точность не нужна, поэтому, в принципе, всё устраивает. Однако, компьютер ниже 4-х ядерного периодически вызывает кратковременные "подвисания" потока, что вызывает заметные на глаз приостановки шагового двигателя и соответственно повышенную вибрацию. Пробовал менять преоритеты, но эффект тот же самый.
Если использовать тики, то, возможно, удалось бы решить проблему. Но если их постоянно отслеживать, то будет то же самое. Необходимо создать что-то типа таймера, который срабатывал бы по прошествию какого-то количества тиков. На http://wiki.freepascal.org/Components_and_Code_examples/ru есть компонент EpikTimer - точный таймер, написанный специально для Lazarus., который, судя по описанию, поддерживает микросекундные интервалы.
- Nanosecond resolution is supported on Intel Pentium versions with a Timestamp Counter.
- Microsecond system clock is the default timebase.
Можно ли при помощи этого компонента получить требуемые задержки? В примерах приводят только секундные задержки, а процедуру типм SleepUS или Timer.Interval=... (микросекунд), там не увидел.

Добавлено спустя 3 минуты 8 секунд:
Самое обидное то, что я у меня есть аналогичная зарубежная программа, которая выдаёт интервалы даже меньше 10 мкс и без подвисаний работает на Pentium-1.
shyub
постоялец
 
Сообщения: 112
Зарегистрирован: 25.11.2014 23:15:19

Re: Таймер с высоким разрешением

Сообщение CRobin » 25.09.2016 18:43:25

Очень возможно, что ваши "подвисания" не связаны с загузкой ядер как таковых, а связаны с миграцией потока между ядрами. Исключите этот аспект (в соседней теме есть решение как), если не поможет, тогда есть еще идеи. ОС я так понимаю Линукс?
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Таймер с высоким разрешением

Сообщение shyub » 25.09.2016 19:16:25

Нет, ОС Windows. По поводу миграции. А разве может запущенный поток произвольно осуществлять миграцию между ядрами? Мне казалось, что онзакрепляется за ядром при создании.
Интересно услвшать ещё идеи, даже если они под Linux. В случае чего могу переписать код под Ubuntu.
shyub
постоялец
 
Сообщения: 112
Зарегистрирован: 25.11.2014 23:15:19

Re: Таймер с высоким разрешением

Сообщение Vadim » 25.09.2016 19:17:55

shyub
Можно попробовать запустить программу на одном определённом ядре и посмотреть, что будет...
Для винды это:
Код: Выделить всё
start /affinity 1 ваша_программа.exe

т.е. запускаем на 1-ом (слева :D ) ядре.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Таймер с высоким разрешением

Сообщение shyub » 25.09.2016 19:26:42

Спасибо. А можно это сделать не через командную строку, а где-то в теле программы?
shyub
постоялец
 
Сообщения: 112
Зарегистрирован: 25.11.2014 23:15:19

Re: Таймер с высоким разрешением

Сообщение CRobin » 25.09.2016 20:40:31

shyub конечно может мигрировать и должен это делать. Убедиться в этом вы можете запустив таск менеджер и посмотрев на график загрузки ЦП. Как прибивать поток к ядру описано в соседней ветке.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Таймер с высоким разрешением

Сообщение mig-31 » 26.09.2016 12:01:30

Нанотаймер только под Линух. На Виндовс 10 микросекунд гарантировано не получите. Системные часы Виндовс 1кГц = 1мс. 1кГц и для стандартной сборки ядра Линух. Под Линух надо ставить ядро с real-time расширением в репозитории почти каждого дистрибутива.

http://forum.lazarus.freepascal.org/index.php/topic,19968.msg114384.html#msg114384
mig-31
постоялец
 
Сообщения: 224
Зарегистрирован: 14.07.2011 13:46:48

Re: Таймер с высоким разрешением

Сообщение wavebvg » 26.09.2016 17:54:04

shyub, всё дело в синхронизации.
Если возможно отказаться от синхронизации с основным потоком, тогда сможете получить очень хорошие результаты. Ну и в этом случае говорить про компоненты несколько странно, ведь синхронизация тоже требует времени (обработчик события, создаваемый по клику на компоненте или его событии, запускает синхронизация с основным потоком и т.д.).
Синхронизация с основным потоком написана без всякого рвения к микросекундам (ведь синхронизация нужна GUI, который сам по себе вещь тормознутая).
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Таймер с высоким разрешением

Сообщение shyub » 26.09.2016 23:38:06

Ребята, дело принципа. Провёл массу эксперементов. Проблема, это моё личное мнение, далеко не в потоках и пр. Ставлю два компьютера (один Pentium-1 второй Core-2 Quard), на первом "висяки", на втором всё нормально. Далее, подключаю к порту логический анализатор (сначала к первому,затем ко второму). На первом перерывы около 100 мс, на втором ококл 0,76 мкс.
Если кому-то интересно, могу провести ещё ряд экспериментов. Скажите что надо сделать, сделаю.

Добавлено спустя 2 минуты 16 секунд:
shyub, всё дело в синхронизации.
Если возможно отказаться от синхронизации с основным потоком, тогда сможете получить очень хорошие результаты.

С большим удовольствием проверю. Давайте код.
shyub
постоялец
 
Сообщения: 112
Зарегистрирован: 25.11.2014 23:15:19

Re: Таймер с высоким разрешением

Сообщение CRobin » 27.09.2016 00:18:08

shyub вам уже несколько человек написали что делать. Пока вы не исключите основную причину, другие эксперименты бесполезны, а их результаты не интересны.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

Re: Таймер с высоким разрешением

Сообщение Mirage » 27.09.2016 00:30:39

shyub писал(а):Ставлю два компьютера (один Pentium-1 второй Core-2 Quard)


ОС одинаковые? А то винда как-то не является ОС реального времени и не гарантирует, что поток приложения не будет остановлен на неопределенное время. Например, чтобы кэш сбросить. Если все время перерывы 100мс, то код в студию.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Таймер с высоким разрешением

Сообщение shyub » 27.09.2016 02:34:08

Код в студию.
ОК. Там слишком много всесг, но основное "в студию".
1. Определяю скорость при запуске:
Код: Выделить всё
    while flagTmks do begin
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Out32(Form1.PEN.Port, RD);
      Out32(Form1.PEN.Port+2, RU);
      Tms:=Tms+1;
    end;

Далее, по срабатыванию таймера flagTmks становится false. На основании Tms я расчитываю время шага и делаю так, где TrT=требуемое количество циклов, чтобы обеспечить длительность шага:
Код: Выделить всё
procedure TMyThread.Execute;
var
  n: Integer;
begin
  while Form1.flagLin or Form1.flagRab or Form1.flagShag do begin
    Synchronize(@Zapros);
    while TrNsg>0 do begin
      for n:=1 to TrT do begin
        Out32(Form1.PEN.Port, TrRD);
        Out32(Form1.PEN.Port+2, TrRU);
      end;
      for n:=1 to TrT do begin
        Out32(Form1.PEN.Port, TrRDi);
        Out32(Form1.PEN.Port+2, TrRUi);
      end;
      Dec(TrNsg);
    end;
    if Form1.flagShag then Form1.flagShag:=false; // Если это один шаг, то выход из потока.
  end;
  Out32(Form1.PEN.Port, TrRD);
  Out32(Form1.PEN.Port+2, TrRU);
  Synchronize(@OffStop);
  Form1.Dflag:=false;
end;

К окончанию цикла ф-ция Zapros подготавливает новые даннные.
Если кому-то интересно, то могу выложить весь код, но там несколько КБ.

Добавлено спустя 12 минут 46 секунд:
Считаю бэто бесполезным занятием. Причины:
1. Перешол на контроллер на базе STM32.
2. Заменил LPT порт на USB, но главное, что перекидываю в контроллер ке шаг, а длину перемещения (он сам всё расчитывает).
3. Нагрузка на ПК вообще снизилась (можно играть на P-1 в игрушку, игрушка тормозит, а движки работают без перебоев).
Как говорится в русской пословице: "не нытьём, так уатаньем", но проект удалось вытащить и сдать.
Всем участникам форума большое спасибо, но тема интересная и хотелось бы её продолжить. У меня есть хорошее оборудование, позволяющее записывать в течении 30 мин. 16 логических сигналов с точностью до 1 нс. Пока оно у меня, хотелось бы поэксперемнетировать.
shyub
постоялец
 
Сообщения: 112
Зарегистрирован: 25.11.2014 23:15:19

Re: Таймер с высоким разрешением

Сообщение Mirage » 27.09.2016 05:14:28

shyub писал(а):К окончанию цикла ф-ция Zapros подготавливает новые даннные.


К окончанию цикла? Данная конструкция (Synchronize) усыпляет поток (что уже тысячи тактов занимает, т.к. переключается контекст), переключается на главный поток, там отрабатывает этот Zapros, и только когда он закончит, просыпается снова наш поток. Конечно тут ни о каких наносекундах речь уже не идет.

Если нужно передавать данные из другого потока, то в данном случае это надо делать так, чтобы обрабатывающий поток не засыпал. Т.е. использовать, например, очередь с методом типа tryPop(), который когда нет данных не зависает, а сразу возвращает управление. И обрабатывающий поток крутит цикл, пока не получит данные, вместо того, чтобы заснуть, например, на критической секции.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 10

Рейтинг@Mail.ru