Приветствую всех!!! Долго не отвечал т.к. был в деревне )) Я все таки решил написать VXD драйвер, который будет управлять программатором. Попробовал реализовать залержку с помощью 2-го канала таймера : т.е. обнулить канал, затем запустить его и в цикле проверять его текущее значение пока оно не будет больше 100 ( к примеру (100мкс)) затем остановить его выполнить нужные действия и потом все сначало (обнулить, запустить, сканировать в цикле). Что бы проверить его я зациклил эту операцию до 100 раз (т.е. 100мкс * 100 = 1 секунда) , но почему-то задержка ,мягко говоря, несколько меньше 1 секунды)) ( ее практически нет ). Стал смотреть через SoftIce и увидел, что текущее значение таймера уже при втором прохождении цикла > 100, т.е. получается, что время одного такта таймера много меньше 1мкс, хотя в книжке написано, что 1мкс. Вот здесь код задержки : Код (Text): ; здесь задержка ;--------------------- mov edi,100 @@loop_1s: ; ставим режим 3 для 2-го канала таймера mov dx,43h mov al,0b6h out dx,al ; загружаем младший байт счетчика mov dx,42h mov al,200 ; 200мкс out dx,al ; загружаем старший байт счетчика mov al,0 out dx,al ; разрешаем работу канала mov dx,61h in al,dx or al,01h out dx,al ; организация задержки 100мкс @@loop_100mks: mov dx,43h mov al,86h out dx,al ; фиксируем текущее значение счетчика mov dx,42h in al,dx ; читаем младший байт счетчика mov ah,al in al,dx ; читаем старший байт счетчика cmp ah,100 ; сравниваем младший байт с 100 jl @@loop_100mks ; если меньше, то сравниваем заново ; иначе останавливаем канал mov dx,61h in al,dx and al,11111110b out dx,al dec edi cmp edi,0 jne @@loop_1s ;--------------------- может кто подскажет поточнее как справиться с такой задержкой ???? ))
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). Насколько я понимаю через него и эмулируется старый таймер.
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). Короче, надо экспериментировать.
Pavia Почитал тут я в инете про него, только что-то не понятно как им пользоваться :\ *** А вот C ф-ция usleep вроде как делает задержку в микросекундах: она под дос или нет?
drmad Как думаешь, имеет ли смысл организовывать задержку 10мкс твоим способом в таком коде : Код (Text): ; ставим режим 3 для 2-го канала таймера mov dx,43h mov al,0b6h out dx,al ; загружаем младший байт счетчика mov dx,42h mov al,24 ; (10мкс/0.84) * 2такта sub al,6 ; <----- !!!!!!!!! корректировка из-за времени выполнения соседних команд out dx,al ; загружаем старший байт счетчика mov al,0 out dx,al ; разрешаем работу канала mov dx,61h in al,dx or al,01h out dx,al ; запоминаем состояние выхода out для дальнейшего сравнения ; читаем слово состояния канала 2 mov dx,43h mov al,11101000b out dx,al mov dx,42h in al,dx and al,10000000b mov bl,al ; сохраняем "out" в bl ; организация задержки 10мкс @@loop_10mks: ; читаем слово состояния канала 2 mov dx,43h mov al,11101000b out dx,al mov dx,42h in al,dx and al,10000000b cmp al,bl je @@loop_10mks ; если равны, то сравниваем заново ; иначе останавливаем канал mov dx,61h in al,dx and al,11111110b out dx,al Здесь наверное только при начальной настройке таймера уже 10мкс получится ? ))
AB_Celitel У меня получилось покороче Код (Text): void delay100() { asm { // Загрузка счетчика mov al, 0EEh out 43h, al sub al, al out 43h, al // Запуск счета mov al, 3 out 61h, al OnceMore: // Подготовить чтение статуса mov al, 0E8h out 43h, al // Читать статус in al, 42h // Проверяем старший бит статуса, это и есть OUT test al, 80h jne OnceMore // Останов счета mov al, 0 out 61h, al } } Ну ладно, раз пошла такая пьянка... Когда-то давно я решал такую-же проблему методом обычного цикла. И делал это примерно так. 1. Будем делать задержку в виде определенного числа циклов: Код (Text): void longcycle(DWORD N) { for (DWORD i=1;i<N;i++); } 2. Как вычислить необходимое число циклов? А вот так: Код (Text): #define RN(x) (float)((float)x.u.LowPart+(float)x.u.HighPart*(float)0xffffffff) #define NNN 100000 LARGE_INTEGER t1, t2, fr; QueryPerformanceFrequency(&fr); // Это частота таймера QueryPerformanceCounter(&t1); // Это t1 (в тиках таймера) longcycle(NNN); // Это произвольная задержка QueryPerformanceCounter(&t2); // Это t2 (в тиках таймера) float t = (RN(t2)-RN(t1))/RN(fr); // Это t2-t1 (в секундах) Составляем пропорцию, на сколько надо зациклить, чтобы получить X секунд? Код (Text): float x=0.000010; n = (DWORD)((x*(float)NNN)/t); 3. Кроме того, необходимо оценить "мертвое время", оно пригодится. Код (Text): QueryPerformanceCounter(&t1); QueryPerformanceCounter(&t2); float tt = (RN(t2)-RN(t1))/RN(fr); // Это мертвое время (в сек) Аналогичная пропорция, сколько циклов в мертвом времени? Код (Text): nn = (DWORD)((tt*(float)NNN)/t); 4. Вот и все, теперь смело выполняем задержку: На 10 мкс: Код (Text): longcycle(n-nn); На 100 мкс: Код (Text): 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 Только я бы еще изменил приоритет потока до максимального, если задержки надо делать большие и много, чтобы посторонние потоки не прерывали работу. Устроит решение?
drmad Спасибо за полезный пример, приму к сведению. )) *** Код (Text): out 43h, al Странно, а masm на такую команду ругается, ему подавай out dx,al :/ *** Код (Text): // Проверяем старший бит статуса, это и есть OUT test al, 80h jne OnceMore Так значит, что при запуске таймера OUT = 0 ?
На моей рабочей железяке это 3014530000, т. е. похоже, что это частота проца и используется rdtsc. Опа... облом. А на домашнем у меня таки 3579545 на такой же самой XP...
Возвращаясь к старой теме. Никто не видел в Инете или где-нибудь еще сводной таблички c величиной кванта времени в разных осях, но чтоб там было все - win95, win98, nt 4 ws (вроде бы 20 мс?), nt 4 sr (вроде бы 120?), 2000 ws ( вроде бы 20?), 2000 sr (вроде бы 240?), xp, 2003 ?
У мну вариант с проверкой бита статуса чего-то не работает Да и на 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 Может кто подскажет более оптимальный вариант?
Оптимальный вариант который бы использовал я - таймер APIC, точность поразительная просто. Тот механизм который используется функцией hal!KeStallExecutionProcessor слишком неэффективен, он использует низкоточный TSC. (Не знаю почему MS$ решила использовать это).
Точность? Поразительная? http://www.overclockers.ru/lab/15487.shtml http://www.overclockers.ru/lab/15495.shtml
Господа, прочитал статьи по ссылкам, но так и не понял в каком направлении копать Собственно задержка нужна при посылке байтов в lpt порт, через который будет вычитываться iso7816-карточка. Затеяно всё это с целью изучить асм ну и узнать чего имеется на карточке.