I have an application that I need to run at 10 ms (100 Hz) on a Windows 7/32 bit computer (other applications will work at the same time). This interrupt may have several minimal (100uSec) responses, but should not drift for a long time. I have a program in which I booted up and used NtSetTimerResolution to set timers for 10 ms resolution, and then created a timer using the CreateTimerQueue / CreateTimereQueueTimer functions using a callback procedure that switches the GPIO output (for now) - this creates the expected square wave while I am not doing anything with the system. When I start several other processes, the accuracy of my square wave comes out of the window. Is there a way to get a higher priority level when interrupting a timer (or is there another timer I can use) that will give a more stable result (maybe SMI)? My code is below and built using the proven x86 build environment for the Windows DDK and runs from the shell with administrator privileges:
#include <windows.h> #include <winioctl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <conio.h> #include <strsafe.h> #include <stdlib.h> #include <stdio.h> #include <winsock2.h> #include <mswsock.h> #pragma warning(disable:4127) // condition expression is constant FARPROC pNtQueryTimerResolution; FARPROC pNtSetTimerResolution; static HANDLE NTDLLModuleHandle; static HINSTANCE hInpOutDll; typedef void ( __stdcall *lpOut32 )( short , short ); typedef short ( __stdcall *lpInp32 )( short ); typedef BOOL ( __stdcall *lpIsInpOutDriverOpen )( void ); //Some global function pointers (messy but fine for an example) lpOut32 gfpOut32; lpInp32 gfpInp32; lpIsInpOutDriverOpen gfpIsInpOutDriverOpen; void CALLBACK TimerProc(void* lpParameter, BOOLEAN TimerOrWaitFired); // MAIN VOID __cdecl main( void ) { ULONG ulMinRes = 0; ULONG ulMaxRes = 0; ULONG ulCurRes = 0; HANDLE phNewQueue; HANDLE phNewTimer; phNewQueue = CreateTimerQueue( ); NTDLLModuleHandle = LoadLibrary( "NTDLL.DLL" ); if( NULL == NTDLLModuleHandle ) { return; } // Get the function pointers, pNtQueryTimerResolution = GetProcAddress( NTDLLModuleHandle, "NtQueryTimerResolution" ); pNtSetTimerResolution = GetProcAddress( NTDLLModuleHandle, "NtSetTimerResolution" ); if( ( pNtQueryTimerResolution == NULL ) || ( pNtSetTimerResolution == NULL ) ) { printf( "unable to link to ddl\n\n\n\n\n\n" ); return; } pNtQueryTimerResolution( &ulMinRes, &ulMaxRes, &ulCurRes ); printf( "MMR: %d %d %d\n", ulMinRes, ulMaxRes, ulCurRes ); ulMaxRes = 100000; pNtSetTimerResolution( ulMaxRes, TRUE, &ulCurRes ); pNtQueryTimerResolution( &ulMinRes, &ulMaxRes, &ulCurRes ); printf( "MMR: %d %d %d\n", ulMinRes, ulMaxRes, ulCurRes ); //Dynamically load the DLL at runtime (not linked at compile time) hInpOutDll = LoadLibrary( "InpOut32.DLL" ); if( hInpOutDll != NULL ) { gfpOut32 = ( lpOut32 )GetProcAddress( hInpOutDll, "Out32" ); gfpInp32 = ( lpInp32 )GetProcAddress( hInpOutDll, "Inp32" ); gfpIsInpOutDriverOpen = ( lpIsInpOutDriverOpen )GetProcAddress( hInpOutDll, "IsInpOutDriverOpen" ); if( gfpIsInpOutDriverOpen( ) ) { gfpOut32( 0xA01, 0x00 ); } else { printf( "unable to create timer system\n\n\n\n\n\n" ); return; } } CreateTimerQueueTimer( &phNewTimer, phNewQueue, TimerProc, NULL, 0, 10, WT_EXECUTEINTIMERTHREAD ); do { Sleep( 1 ); } while( TRUE ); } void CALLBACK TimerProc(void* lpParameter, BOOLEAN TimerOrWaitFired) { WORD wData; UNREFERENCED_PARAMETER ( lpParameter ); UNREFERENCED_PARAMETER ( TimerOrWaitFired ); wData = gfpInp32( 0xA00 ); wData++; gfpOut32( 0xA00, wData ); }
source share