It is necessary to create a stable interrupt of 10 ms

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:

/* Abstract: Simple console test app for a 10mSec timer interrupt service Enviroment: Administrator Mode */ /* INCLUDES */ #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 ); } 
+4
source share
2 answers

You can use SetThreadPriority to give priority to a critical thread. In this case, you probably need to explicitly create the stream and use CreateWaitableTimerEx , SetWaitableTimerEx and WaitForSingleObjectEx instead of CreateTimerQueueTimer . Make sure that the critical thread never spends too much time between expectations, or that Windows may stop working properly.

This may not be enough if the maximum lag is 100 microseconds. You may need to set the process priority class REALTIME_PRIORITY_CLASS using the SetPriorityClass function, but make sure your program never holds the processor for a long time or Windows stops working properly. In particular, if your program freezes, the entire OS will freeze; In this situation, it is not possible to stop the program without turning off the power.

Even this may not be enough. Windows is not a real-time operating system, and it may not be possible to get it to do what you ask.

+2
source

My experience with Windows and the millisecond is that it is not reliable. I measured the Sleep api with an oscilloscope through a Nusbio device. And Sleep (0) is different from the fact that you don't call the method at all. Sleep (5) and Sleep (15) give an inconsistent result sometime, when the expectation is the same.

If you need this accuracy, you need a microcontroller that can talk to your Windows application.

0
source

Source: https://habr.com/ru/post/1414046/


All Articles