Формирование задержки

Тема в разделе "WASM.WIN32", создана пользователем AB_Celitel, 21 июл 2006.

  1. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    Приветствую всех!!!
    Долго не отвечал т.к. был в деревне :)))

    Я все таки решил написать VXD драйвер, который будет управлять программатором.
    Попробовал реализовать залержку с помощью 2-го канала таймера : т.е. обнулить канал,
    затем запустить его и в цикле проверять его текущее значение пока оно не будет больше
    100 ( к примеру (100мкс)) затем остановить его выполнить нужные действия и потом все сначало
    (обнулить, запустить, сканировать в цикле). Что бы проверить его я зациклил эту операцию
    до 100 раз (т.е. 100мкс * 100 = 1 секунда) , но почему-то задержка ,мягко говоря, несколько
    меньше 1 секунды:))) ( ее практически нет ). Стал смотреть через SoftIce и увидел, что
    текущее значение таймера уже при втором прохождении цикла > 100, т.е. получается, что
    время одного такта таймера много меньше 1мкс, хотя в книжке написано, что 1мкс.

    Вот здесь код задержки :

    Код (Text):
    1. ; здесь задержка
    2. ;---------------------
    3.  
    4. mov edi,100
    5.  
    6. @@loop_1s:
    7. ; ставим режим 3 для 2-го канала таймера
    8.  mov dx,43h
    9.  mov al,0b6h
    10.  out dx,al
    11. ; загружаем младший байт счетчика
    12.  mov dx,42h
    13.  mov al,200  ; 200мкс
    14.  out dx,al
    15. ; загружаем старший байт счетчика
    16.  mov al,0
    17.  out dx,al
    18. ; разрешаем работу канала
    19.  mov dx,61h
    20.  in al,dx
    21.  or al,01h
    22.  out dx,al
    23. ; организация задержки 100мкс
    24. @@loop_100mks:
    25.  mov dx,43h
    26.  mov al,86h
    27.  out dx,al ; фиксируем текущее значение счетчика
    28.  mov dx,42h
    29.  in al,dx ; читаем младший байт счетчика
    30.  mov ah,al
    31.  in al,dx ; читаем старший байт счетчика
    32.  cmp ah,100 ; сравниваем младший байт с 100
    33.  jl @@loop_100mks  ; если меньше, то сравниваем заново
    34. ; иначе останавливаем канал
    35.  mov dx,61h
    36.  in al,dx
    37.  and al,11111110b
    38.  out dx,al
    39.  
    40.  dec edi
    41.  cmp edi,0
    42.  jne @@loop_1s
    43.  
    44. ;---------------------
    может кто подскажет поточнее как справиться с такой задержкой ???? :)))
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    AB_Celitel
    Какие микра секунды?
    Вот твои такты 1193181,666/200, а вот и время одного такта 200/1193181=0,167 *10^-3c=0,167мс
    А микра это 10^-6.
    Я бы попробовал через PM TIMER эта зверюга завется
    High-Precision Event Timer
    Построенна она на 14.31818Мгц генераторе.
    И его задержка составляет вот столько : 69841279 fs (femptoseconds 10^-15 seconds).
    Насколько я понимаю через него и эмулируется старый таймер.
     
  3. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    AB_Celitel

    Ты неправильно себе представляешь работу таймера в 3-м режиме.

    1. При запуске в счетчик загружается некоторое исходное значение.
    2. На счетчик непрерывно поступают кварцованные импульсы с частотой 1.19 Мгц (т.е. период между двумя импульсами 0.84 мкс).
    3. По каждому импульсу (т.е. каждые 0.84 мкс) из счетчика вычитается число 2. (!!! ИМЕННО ТАК !!!)
    4. Как только счетчик достигнет 0, он перезагружается в прежнее значение, и все повторяется. Кстати, по этому событию (по обнулению счетчика) опрокидывается (т.е изменяется из 0 в 1, и наоборот) сигнал OUT на выходе таймерного канала.

    Допустим, тебе нужна задержка 100 мкс. В этой задержке укладывается 100/0.84=119 тиков кварца. По каждому тику из счетчика вычитается 2, значит за это время вычтется 238. Тогда делаешь так: принудительно загружаешь в счетчик значение 238 (младший байт EE, старший 0), запускаешь таймер и ждешь перезагрузки счетчика: 1) либо счетчик скакнет назад, типа: 10... 8... 6... 4... 2... 238... 236...; 2) либо сигнал OUT инвертируется (это, кстати, проще).

    Но, честно говоря, я бы не рекомендовал юзать этот метод для 10-мкс задержек. По крайней мере, на тех машинах, на которых я работал, у этого метода были большие накладные расходы - примерно 2 мкс на каждое обращение к порту. Можно попробовать минимизировать обращения к портам, например, установить режим чтения только младшего байта счетчика (старший же все равно 0). Короче, надо экспериментировать.
     
  4. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    Pavia

    Почитал тут я в инете про него, только что-то не понятно как им пользоваться :\

    ***
    А вот C ф-ция usleep вроде как делает задержку в микросекундах: она под дос или нет?
     
  5. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    drmad

    Спасибо, шас попробую :)))
     
  6. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    AB_Celitel
    Ну, есть ещё и nanosleep в стандартной сишной либе, но это ни о чём не говорит.
     
  7. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    drmad

    Огромное спасибо, все отлично работает!!! Уф, ну прямо как гора с плеч :))))
     
  8. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    drmad

    Как думаешь, имеет ли смысл организовывать задержку 10мкс твоим способом в таком коде :

    Код (Text):
    1. ; ставим режим 3 для 2-го канала таймера
    2.  mov dx,43h
    3.  mov al,0b6h
    4.  out dx,al
    5. ; загружаем младший байт счетчика
    6.  mov dx,42h
    7.  mov al,24  ; (10мкс/0.84) * 2такта
    8.  sub al,6  ; <-----  !!!!!!!!!  корректировка из-за времени выполнения соседних команд
    9.  out dx,al
    10. ; загружаем старший байт счетчика
    11.  mov al,0
    12.  out dx,al
    13. ; разрешаем работу канала
    14.  mov dx,61h
    15.  in al,dx
    16.  or al,01h
    17.  out dx,al
    18. ; запоминаем состояние выхода out для дальнейшего сравнения
    19. ; читаем слово состояния канала 2
    20.  mov dx,43h
    21.  mov al,11101000b
    22.  out dx,al
    23.  mov dx,42h
    24.  in al,dx
    25.  and al,10000000b
    26.  mov bl,al ; сохраняем "out" в bl
    27.  
    28. ; организация задержки 10мкс
    29. @@loop_10mks:
    30. ; читаем слово состояния канала 2
    31.  mov dx,43h
    32.  mov al,11101000b
    33.  out dx,al
    34.  mov dx,42h
    35.  in al,dx
    36.  and al,10000000b
    37.  cmp al,bl
    38.  je  @@loop_10mks ; если равны, то сравниваем заново
    39.  
    40. ; иначе останавливаем канал
    41.  mov dx,61h
    42.  in al,dx
    43.  and al,11111110b
    44.  out dx,al
    Здесь наверное только при начальной настройке таймера уже 10мкс получится ? :)))
     
  9. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    AB_Celitel
    У меня получилось покороче :)
    Код (Text):
    1. void delay100() {
    2.  asm {
    3. // Загрузка счетчика
    4.         mov     al, 0EEh
    5.         out     43h, al
    6.         sub     al, al
    7.         out     43h, al
    8. // Запуск счета
    9.         mov     al, 3
    10.         out     61h, al
    11. OnceMore:
    12. // Подготовить чтение статуса
    13.         mov     al, 0E8h
    14.         out     43h, al
    15. // Читать статус
    16.         in      al, 42h
    17. // Проверяем старший бит статуса, это и есть OUT
    18.         test    al, 80h
    19.         jne     OnceMore
    20. // Останов счета
    21.         mov     al, 0
    22.         out     61h, al
    23.   }
    24. }
    Ну ладно, раз пошла такая пьянка... Когда-то давно я решал такую-же проблему методом обычного цикла. И делал это примерно так.

    1. Будем делать задержку в виде определенного числа циклов:
    Код (Text):
    1. void longcycle(DWORD N) {
    2.  for (DWORD i=1;i<N;i++);
    3. }
    2. Как вычислить необходимое число циклов? А вот так:
    Код (Text):
    1. #define RN(x) (float)((float)x.u.LowPart+(float)x.u.HighPart*(float)0xffffffff)
    2. #define NNN 100000
    3.  
    4. LARGE_INTEGER t1, t2, fr;
    5.  
    6.  QueryPerformanceFrequency(&fr); // Это частота таймера
    7.  QueryPerformanceCounter(&t1);    // Это t1 (в тиках таймера)
    8.  longcycle(NNN);                               // Это произвольная задержка
    9.  QueryPerformanceCounter(&t2);   // Это t2 (в тиках таймера)
    10.  float t =  (RN(t2)-RN(t1))/RN(fr); // Это t2-t1 (в секундах)
    Составляем пропорцию, на сколько надо зациклить, чтобы получить X секунд?

    Код (Text):
    1. float x=0.000010;
    2.  n = (DWORD)((x*(float)NNN)/t);
    3. Кроме того, необходимо оценить "мертвое время", оно пригодится.

    Код (Text):
    1. QueryPerformanceCounter(&t1);
    2. QueryPerformanceCounter(&t2);
    3. float tt = (RN(t2)-RN(t1))/RN(fr); // Это мертвое время (в сек)
    Аналогичная пропорция, сколько циклов в мертвом времени?

    Код (Text):
    1.  nn = (DWORD)((tt*(float)NNN)/t);
    4. Вот и все, теперь смело выполняем задержку:

    На 10 мкс:

    Код (Text):
    1. longcycle(n-nn);
    На 100 мкс:

    Код (Text):
    1. longcycle(n*10-nn);
    Ну и вот и ризалты, на разных машинах, в разных осях:

    GenuineIntel 80686 367 MHz Win 95/98/ME 4.10 2222 A
    Cycles=100000, delay= 0.000550 s
    Dead time 0.000004 s, nn=762
    Cycles= 1818, delay= 0.000009 s
    Cycles= 1818, delay= 0.000011 s
    Cycles= 1818, delay= 0.000011 s
    Cycles= 1818, delay= 0.000011 s
    Cycles= 1818, delay= 0.000011 s

    Cycles= 18180, delay= 0.000102 s
    Cycles= 18180, delay= 0.000100 s
    Cycles= 18180, delay= 0.000100 s
    Cycles= 18180, delay= 0.000101 s
    Cycles= 18180, delay= 0.000101 s

    GenuineIntel 801586 1999 MHz Win NT/2K/XP 5.0 2195 Service Pack 3
    Cycles=100000, delay= 0.000076 s
    Dead time 0.000001 s, nn=910
    Cycles= 13160, delay= 0.000011 s
    Cycles= 13160, delay= 0.000010 s
    Cycles= 13160, delay= 0.000010 s
    Cycles= 13160, delay= 0.000010 s
    Cycles= 13160, delay= 0.000010 s

    Cycles=131600, delay= 0.000099 s
    Cycles=131600, delay= 0.000099 s
    Cycles=131600, delay= 0.000099 s
    Cycles=131600, delay= 0.000099 s
    Cycles=131600, delay= 0.000099 s

    Только я бы еще изменил приоритет потока до максимального, если задержки надо делать большие и много, чтобы посторонние потоки не прерывали работу. Устроит решение?
     
  10. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    drmad

    Спасибо за полезный пример, приму к сведению. :)))

    ***
    Код (Text):
    1. out     43h, al
    Странно, а masm на такую команду ругается, ему подавай out dx,al :/

    ***
    Код (Text):
    1.  
    2. // Проверяем старший бит статуса, это и есть OUT
    3.         test    al, 80h
    4.         jne     OnceMore
    Так значит, что при запуске таймера OUT = 0 ?
     
  11. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    AB_Celitel

    Так значит, что при запуске таймера OUT = 0 ?

    Нет, 1. Это мой косяк. :)
     
  12. AB_Celitel

    AB_Celitel New Member

    Публикаций:
    0
    Регистрация:
    9 июл 2005
    Сообщения:
    72
    Адрес:
    Россия, г.Иваново
    drmad

    Угу :)))
     
  13. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    На моей рабочей железяке это 3014530000, т. е. похоже, что это частота проца и используется rdtsc.

    Опа... облом. А на домашнем у меня таки 3579545 на такой же самой XP...
     
  14. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    Возвращаясь к старой теме. Никто не видел в Инете или где-нибудь еще сводной таблички c величиной кванта времени в разных осях, но чтоб там было все - win95, win98, nt 4 ws (вроде бы 20 мс?), nt 4 sr (вроде бы 120?),
    2000 ws ( вроде бы 20?), 2000 sr (вроде бы 240?), xp, 2003 ?
     
  15. xlx

    xlx New Member

    Публикаций:
    0
    Регистрация:
    17 июл 2008
    Сообщения:
    3
    У мну вариант с проверкой бита статуса чего-то не работает :dntknw:
    Да и на gate2 таймер тоже не реагирует... может что под виндой юзаю?

    Заработало только в таком варианте:

    C segment
    org 100h
    start:

    mov al,10111000b
    out 43h,al ; kanal 2, read/write, mode 4, binary

    mov ax,0FFFFh ; znacheniye zaderjki
    out 42h,al
    shr al,8 ; zapis znacheniya zaderjki v port
    out 42h,al

    delay_cycle:

    mov al,11011000b
    out 43h,al
    in al,42h
    shl ax,8
    in al,42h
    test ax,0FFFFh

    jnz delay_cycle

    exit:
    mov ax,4c00h
    int 21h

    C ends
    end start

    Может кто подскажет более оптимальный вариант?
     
  16. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Оптимальный вариант который бы использовал я - таймер APIC, точность поразительная просто. Тот механизм который используется функцией hal!KeStallExecutionProcessor слишком неэффективен, он использует низкоточный TSC. (Не знаю почему MS$ решила использовать это).
     
  17. xlx

    xlx New Member

    Публикаций:
    0
    Регистрация:
    17 июл 2008
    Сообщения:
    3
    А как его програмить? Из под окна дос в винде это будет работать?
     
  18. drmad

    drmad New Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    332
    Адрес:
    Russia
    Точность? Поразительная?

    http://www.overclockers.ru/lab/15487.shtml
    http://www.overclockers.ru/lab/15495.shtml
     
  19. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Да! Поразительная!
    У меня на маме гигабайт c P4 нет никакой пляски частот, проверено.
     
  20. xlx

    xlx New Member

    Публикаций:
    0
    Регистрация:
    17 июл 2008
    Сообщения:
    3
    Господа, прочитал статьи по ссылкам, но так и не понял в каком направлении копать :)
    Собственно задержка нужна при посылке байтов в lpt порт, через который будет вычитываться iso7816-карточка.
    Затеяно всё это с целью изучить асм ну и узнать чего имеется на карточке.