diff --git a/flight/OpenPilot/Makefile.win32 b/flight/OpenPilot/Makefile.win32 index 51dc8c0f7..c8a46542a 100644 --- a/flight/OpenPilot/Makefile.win32 +++ b/flight/OpenPilot/Makefile.win32 @@ -41,7 +41,7 @@ USE_BOOTLOADER ?= NO CODE_SOURCERY ?= NO # Toolchain prefix (i.e arm-elf- -> arm-elf-gcc.exe) -TCHAIN_PREFIX ?= "" +TCHAIN_PREFIX ?= mingw32- # Remove command is different for Code Sourcery on Windows REMOVE_CMD ?= rm @@ -221,7 +221,7 @@ EXTRA_LIBDIRS = # EXTRA_LIBS = xyz abc efsl # for newlib-lpc (file: libnewlibc-lpc.a): # EXTRA_LIBS = newlib-lpc -EXTRA_LIBS = WS2_32 +EXTRA_LIBS = WS2_32 Winmm # Path to Linker-Scripts LINKERSCRIPTPATH = $(PIOSSTM32F10X) @@ -281,7 +281,7 @@ CSTANDARD = -std=gnu99 # Flags for C and C++ (arm-elf-gcc/arm-elf-g++) ifeq ($(DEBUG),YES) -CFLAGS = -g$(DEBUGF) -DDEBUG +CFLAGS = -g endif CFLAGS += -DARCH_WIN32 @@ -331,11 +331,11 @@ LDFLAGS += -lgcc # Define programs and commands. CC = $(TCHAIN_PREFIX)gcc CPP = $(TCHAIN_PREFIX)g++ -AR = $(TCHAIN_PREFIX)ar -OBJCOPY = $(TCHAIN_PREFIX)objcopy -OBJDUMP = $(TCHAIN_PREFIX)objdump -SIZE = $(TCHAIN_PREFIX)size -NM = $(TCHAIN_PREFIX)nm +AR = ar +OBJCOPY = objcopy +OBJDUMP = objdump +SIZE = size +NM = nm REMOVE = $(REMOVE_CMD) -f ###SHELL = sh ###COPY = cp @@ -383,11 +383,13 @@ lss: $(OUTDIR)/$(TARGET).lss sym: $(OUTDIR)/$(TARGET).sym hex: $(OUTDIR)/$(TARGET).hex bin: $(OUTDIR)/$(TARGET).bin +exe: $(OUTDIR)/$(TARGET).exe # Default target. #all: begin gccversion sizebefore build sizeafter finished end #all: begin gccversion build sizeafter finished end -all: elf +#all: elf +all: exe ifeq ($(LOADFORMAT),ihex) build: elf hex lss sym @@ -489,9 +491,15 @@ endif # use $(CC) for C-only projects or $(CPP) for C++-projects: $(CC) $(THUMB) $(CFLAGS) $(ALLOBJ) --output $@ $(LDFLAGS) # $(CPP) $(THUMB) $(CFLAGS) $(ALLOBJ) --output $@ $(LDFLAGS) -#create a windows-usable .exe file - $(OBJCOPY) $(OUTDIR)/$(TARGET).elf $(OUTDIR)/$(TARGET).exe +# Link: create EXE output file from object files. +.SECONDARY : $(TARGET).exe +.PRECIOUS : $(ALLOBJ) +%.exe: $(ALLOBJ) + @echo $(MSG_LINKING) $@ +# use $(CC) for C-only projects or $(CPP) for C++-projects: + $(CC) $(THUMB) $(CFLAGS) $(ALLOBJ) --output $@ $(LDFLAGS) +# $(CPP) $(THUMB) $(CFLAGS) $(ALLOBJ) --output $@ $(LDFLAGS) # Assemble: create object files from assembler source files. define ASSEMBLE_TEMPLATE @@ -576,6 +584,7 @@ clean_list : $(REMOVE) $(OUTDIR)/$(TARGET).bin $(REMOVE) $(OUTDIR)/$(TARGET).sym $(REMOVE) $(OUTDIR)/$(TARGET).lss + $(REMOVE) $(OUTDIR)/$(TARGET).exe $(REMOVE) $(ALLOBJ) $(REMOVE) $(LSTFILES) $(REMOVE) $(DEPFILES) @@ -604,5 +613,5 @@ endif # Listing of phony targets. .PHONY : all begin finish end sizebefore sizeafter gccversion \ -build elf hex bin lss sym clean clean_list program +build exe elf hex bin lss sym clean clean_list program diff --git a/flight/PiOS.win32/inc/FreeRTOSConfig.h b/flight/PiOS.win32/inc/FreeRTOSConfig.h index 298a7c6f1..e1f55991f 100644 --- a/flight/PiOS.win32/inc/FreeRTOSConfig.h +++ b/flight/PiOS.win32/inc/FreeRTOSConfig.h @@ -24,7 +24,7 @@ #define configUSE_IDLE_HOOK 1 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) -#define configTICK_RATE_HZ ( ( portTickType ) 1000 ) +#define configTICK_RATE_HZ ( ( portTickType ) 200 ) #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 45 * 1024 ) ) diff --git a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c index 03c0930b5..c33d4c48e 100644 --- a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c +++ b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c @@ -90,6 +90,7 @@ typedef struct tskTaskControlBlock tskTCB *debug_task_handle; + /* Win32 simulator doesn't really use a stack. Instead It just keep some task specific info in the pseudostack @@ -102,37 +103,49 @@ typedef struct HANDLE hThread; /* handle of thread associated with task */ HANDLE hSemaphore; /* Semaphore thread (task) waits on at start and after yielding */ portSTACK_TYPE dwGlobalIsr; /* mask used to enable/disable interrupts */ - xTaskHandle hTask; /* Task handle so we know the name of this task */ BOOL yielded; /* Need to know how task went out of focus */ }SSIM_T; #define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 ) -#define DEBUG_OUTPUT +//#define DEBUG_OUTPUT //#define ERROR_OUTPUT #ifdef DEBUG_OUTPUT - #define debug_printf(...) ( (WaitForSingleObject(hPrintfMutex, INFINITE)|1)?( \ +/* #define debug_printf(...) ( (WaitForSingleObject(hPrintfMutex, INFINITE)|1)?( \ ( \ (NULL != (debug_task_handle = (tskTCB *) pxCurrentTCB ))? \ (fprintf( stderr, "%20s\t%20s\t%i: ",debug_task_handle->pcTaskName,__func__,__LINE__)): \ (fprintf( stderr, "%20s\t%20s\t%i: ","__unknown__",__func__,__LINE__)) \ |1)?( \ ((fprintf( stderr, __VA_ARGS__ )|1)?ReleaseMutex( hPrintfMutex ):0) \ - ):0 ):0 ) + ):0 ):0 ) */ +#define debug_printf(...) ( ( (NULL != (debug_task_handle = (tskTCB *) pxCurrentTCB ))? \ + (fprintf( stderr, "%20s\t%20s\t%i: ",debug_task_handle->pcTaskName,__func__,__LINE__)): \ + (fprintf( stderr, "%20s\t%20s\t%i: ","__unknown__",__func__,__LINE__)) \ + |1)? \ + fprintf( stderr, __VA_ARGS__ ) : 0 \ + ) #define debug_error debug_printf #else #ifdef ERROR_OUTPUT - #define debug_error(...) ( (WaitForSingleObject(hPrintfMutex, INFINITE)|1)?( \ +/* #define debug_error(...) ( (WaitForSingleObject(hPrintfMutex, INFINITE)|1)?( \ ( \ (NULL != (debug_task_handle = (tskTCB *) pxCurrentTCB ))? \ (fprintf( stderr, "%20s\t%20s\t%i: ",debug_task_handle->pcTaskName,__func__,__LINE__)): \ (fprintf( stderr, "%20s\t%20s\t%i: ","__unknown__",__func__,__LINE__)) \ |1)?( \ ((fprintf( stderr, __VA_ARGS__ )|1)?ReleaseMutex( hPrintfMutex ):0) \ - ):0 ):0 ) + ):0 ):0 )*/ + +#define debug_error(...) ( ( (NULL != (debug_task_handle = (tskTCB *) pxCurrentTCB ))? \ + (fprintf( stderr, "%20s\t%20s\t%i: ",debug_task_handle->pcTaskName,__func__,__LINE__)): \ + (fprintf( stderr, "%20s\t%20s\t%i: ","__unknown__",__func__,__LINE__)) \ + |1)? \ + fprintf( stderr, __VA_ARGS__ ) : 0 \ + ) #define debug_printf(...) #else @@ -150,10 +163,6 @@ typedef struct volatile DWORD dwPendingIsr; // pending interrupts HANDLE hIsrInvoke; // event to signal an interrupt HANDLE hIsrMutex; // mutex to protect above 2 -#if defined(DEBUG_OUTPUT) || defined(ERROR_OUTPUT) -HANDLE hPrintfMutex;// mutex for debug_printf() and debug_error() -#endif -SSIM_T *pxLastAddedTCB; /****************************************************************************** National variables @@ -175,6 +184,7 @@ ESWI_ID; unsigned portLONG ulCriticalNesting = ( unsigned portLONG ) 9999; void (*vIsrHandler[CPU_INTR_COUNT])(void); +UINT msPerTick; //Returned from timeGetDevCaps() #if portDEBUG == 1 @@ -209,18 +219,26 @@ static DWORD WINAPI tick_generator(LPVOID lpParameter) HANDLE hTimer; LARGE_INTEGER liDueTime; HANDLE hObjList[2]; + float before, after; hTimer = CreateWaitableTimer(NULL, TRUE, NULL); - liDueTime.QuadPart = -20000; // 1ms interval + liDueTime.QuadPart = -(50000 - 10000*(int)msPerTick); // 5ms - + //there is always another tick during WaitForMultipleObjects() while waiting + //for the mutex, so reduce the wait time by 1 tick hObjList[0] = hIsrMutex; hObjList[1] = hTimer; for(;;) { + before = (float)clock()/CLOCKS_PER_SEC; + debug_printf("tick before, %f\n", before); SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE); WaitForMultipleObjects(2, hObjList, TRUE, INFINITE); - + after = (float)clock()/CLOCKS_PER_SEC; + debug_printf("tick after, %f\n", after); + debug_printf("diff: %f\n", after - before); + // generate the tick interrupt dwPendingIsr |= (1< 2) + { + printf("Warning: your system timer has a low resolution.\n"); + printf("Either decrease the tick rate, or get a better PC!\n"); + } + timeBeginPeriod(tc.wPeriodMin); + #if configUSE_PREEMPTION != 0 SetThreadPriority(CreateThread(NULL, 0, tick_generator, NULL, 0, NULL), THREAD_PRIORITY_ABOVE_NORMAL); #endif - //printf("got here!\n"); - //printf("%i\n", (int) pxCurrentTCB); - //debug_printf("created system objects\n"); - //printf("got here again!\n"); } /****************************************************************************** @@ -294,14 +317,13 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE psSim->yielded = FALSE; psSim->hThread = CreateThread(NULL, 0, TaskSimThread, psSim, CREATE_SUSPENDED, NULL); ok=SetThreadPriority(psSim->hThread, THREAD_PRIORITY_IDLE); - pxLastAddedTCB = psSim; return (portSTACK_TYPE *) psSim; } portBASE_TYPE xPortStartScheduler( void ) { BOOL bSwitch; - SSIM_T *psSim, *psSimOld; + SSIM_T *psSim; DWORD dwIntr; int i, iIsrCount; HANDLE hObjList[2]; @@ -363,6 +385,7 @@ portBASE_TYPE xPortStartScheduler( void ) SuspendThread(psSim->hThread); vTaskIncrementTick(); + debug_printf("Sending tick ack...\n"); SetEvent(hTickAck); break; @@ -378,33 +401,17 @@ portBASE_TYPE xPortStartScheduler( void ) if(bSwitch) { - psSimOld = psSim; vTaskSwitchContext(); + debug_printf("switching context\n"); psSim=(SSIM_T *)*pxCurrentTCB; - if(psSimOld != psSim) - { - ulCriticalNesting = psSim->ulCriticalNesting; - dwGlobalIsr = psSim->dwGlobalIsr; + ulCriticalNesting = psSim->ulCriticalNesting; + dwGlobalIsr = psSim->dwGlobalIsr; - if(psSim->yielded) { - psSim->yielded = FALSE; - ReleaseSemaphore(psSim->hSemaphore, 1, NULL); // awake next task - } else { - ResumeThread(psSim->hThread); - } - debug_printf("switched context\n"); - } - else - { - //Oops, we just suspended the task that we want to resume! - //TODO: resolve this before it happens - if(psSim->yielded) { - psSim->yielded = FALSE; - ReleaseSemaphore(psSim->hSemaphore, 1, NULL); // awake next task - } else { - ResumeThread(psSim->hThread); - } - debug_printf("didn't switch context\n"); + if(psSim->yielded) { + psSim->yielded = FALSE; + ReleaseSemaphore(psSim->hSemaphore, 1, NULL); // awake next task + } else { + ResumeThread(psSim->hThread); } } @@ -493,6 +500,8 @@ int iPortSetIsrHandler(int iNo, void (*handler)(void)) { if(iNo < CPU_INTR_COUNT) { if(hIsrDispatcher) { + //SSIM_T *psSim=(SSIM_T *)*pxCurrentTCB; + WaitForSingleObject(hIsrMutex, INFINITE); vIsrHandler[iNo]=handler; ReleaseMutex(hIsrMutex); @@ -586,10 +595,3 @@ void vPortExitCritical( void ) } } } - -void vPortAddTaskHandle( void *pxTaskHandle ) -{ - //printf("got here!\n"); - //printf("%i\n", (int)pxLastAddedTCB); - pxLastAddedTCB->hTask = (xTaskHandle)pxTaskHandle; -} diff --git a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c.documentation.txt b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c.documentation.txt deleted file mode 100644 index 022ab59df..000000000 --- a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/port.c.documentation.txt +++ /dev/null @@ -1,188 +0,0 @@ -File: port.c.documentation.txt -Author: Corvus Corax -Desc: Description of port.c Functions and Directions about porting. -See FreeRTOS documentation ebook for details. - - -FreeRTOS is an architecture independent real time operating system. -Most architecture dependant code sits in a single file: port.c -Architecture dependant definitions sit in: portmacro.h - -Other important files: - -Source/portable/MemMang/head_3.c - memory management - very simple. Provides -functions like malloc and free - very easy to make a wrapper for on any system -that provides memory management. - -FreeRTOS has internal scheduling. The real time scheduler sits in Source/task.c and calls low level functions of port.c for thread management. - -For that port.c needs to provide functions to switch between threads on -request, as well as a tick handler that preempts threads on a periodic basis. - -Only one FreeRTOS thread is active at any time! - - -port.c provides the API defined in portmacro.h. - -Only a subset of the functions is explained here (with the naming from the -posix port. Their macros are sometimes named a bit different) - - -void vPortEnterCritical(void); - -This function is called if a thread enters a "critical section". -In a critical sections the thread must not be preempted. - -(To preempt a thread means to halt its execution when a timer interrupt comes -in, and give execution to another thread) -This function should increase a counter for that thread, since several -"Critical Sections" could be cascaded. Only if the outermost critical section -is exited, is preemtion allowed again. - -void vPortExitCritical(void); -This function is called if a thread leaves a "critical section". -If a thread leaves the outermost critical section, the scheduler is allowed to -preempt it on timer interrupt (or other interrupts) - - -void vPortEnableInterrupts(void); -void vPortDisableInterrupts(void); - -functions to enable and disable interrupts. On "real systems" this means all -interrupts including IO. When "simulating" this means the tick handler/ timer -/ timer interrupt. The tick handler is supposed to not do anything if interrupts are disabled. - - -portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, -pdTASK_CODE pxCode, void *pvParameters ); - -Used to initialize a new thread. The stack memory area, command line -parameters for this task and the entry function (pxCode) are given - -This function needs to initialize the new task/thread, but suspend it -immediately. It is only to be executed later if the scheduler says so. - -returns pxTopOfStack if success and 0 on failure. - -THIS WILL BE THE FIRST FUNCTION FreeRTOS CALLS. -The first thread to be created is likely the idle thread. At this time the -scheduler has not been started yet. Therefore it's important to start all -threads in suspended state! - -void vPortEndScheduler(void); - -Needs to end the scheduler (and as such all Tasks/threads) This means FreeRTOS -terminates - as in (simulated) system shutdown. - - -portBASE_TYPE xPortStartScheduler(void); - -This function doesn't return until someone (another thread) calls -vPortEndScheduler(). You can set up your timer and tick handler here and start -the first thread. Then do what a scheduler does (manage threads) - - -vPortYield() - -Sometimes threads go sleeping on purpose (for example during one of FreeRTOS -system calls - including sleep() ) -This function should send the thread that calls it into suspended state and -not return until the scheduler gives back execution to this thread. - - -=========== -The scheduler. - -What your scheduler needs to do: - -Basically what your self written scheduler is allowed to do is the "dirty -work" for the high level scheduler logic provided by FreeRTOS task.c - -The scheduler is supposed to run a timer interrupt/tick handler that gets -called every portTICK_RATE_MICROSECONDS microseconds. -That value is defined somewhere in OpenPilot and has to be exact as well as -the same on all architectures. - -If you cannot set up a timer with that accuracy you are screwed! - -Anyway. Every time the timer tick happens, you have to - -- check whether you are allowed to execute the tick handler. - If interrupts are disabled and/or the thread is in a critical section, the - tick handler should do nothing - -- Tell FreeRTOS that the tick has happened - Increment the Tick Count using the FreeRTOS function - vTaskIncrementTick(); - -- If preemption is enabled (and in OpenPilot it is!) - Tell the high level Scheduler of FreeRTOS to do its magic, using the - function - vTaskSwitchContext(); - -- You can find out which thread is SUPPOSED to be running with the function - xTaskGetCurrentTaskHandle(); - -- If this is for some reason not the currently running thread, SUSPEND that - thread with whatever method possible (signals, events, operating system - thread.suspend() - I don't know how to do that in Qt. - -- Make the thread returned by xTaskGetCurrentTaskHandle() resume operation as - normal. - -- Make sure that when you return from the tick handler, exactly one thread is - running and that is the one by xTaskGetCurrentTaskHandle() and all others - are suspended! - - - -On top of that, threads can suspend themselves just like that. That happens -every time they call any blocking FreeRTOS function. - -They do that with above mentioned function - -vPortYield() - -When vPortYield is called your scheduler must: - -- Tell the high level Scheduler of FreeRTOS to do its magic, using the - function - vTaskSwitchContext(); - -- You can then find out which thread is SUPPOSED to be running with the function - xTaskGetCurrentTaskHandle(); - -- Make sure that the thread calling this function SUSPENDS and the thread - returned by xTaskGetCurrentTaskHandle() gets executed. Be aware that they - could be the same in which case vPortYield does exactly NOTHING! - -- This function does not return (since the current thread is sent to sleep) - until the scheduler makes it wake up - either by the tick handler, or by - another thread calling vPortYield(). - -- So it must not ever return until xTaskGetCurrentTaskHandle() says the - calling thread is the current task handle. - -- Then it returns to the caller. - - - -===== - -What emthod you use to send threads/tasks to sleep and wake them up again is -up to you. - -The posix implementation uses signals and a signal handler in each thread that -sleeps until a resume signal is received - -The native STM32 implementation manually switches contexts by and uses actual -system interrupts -(so does the native x86 implementation) - -The native Win32 implementation uses win32 API calls to manipulate windows -threads (windows actually provides a call to remote-suspend and resume a -thread - posix doesn't) - -I have no clue what measures for thread control and suspension/interruption Qt -offers. (I hope there are some) - diff --git a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/portmacro.h b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/portmacro.h index c0aff14ef..4090216b8 100644 --- a/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/portmacro.h +++ b/flight/PiOS.win32/win32/Libraries/FreeRTOS/Source/portable/GCC/Win32/portmacro.h @@ -56,6 +56,7 @@ #include #include #include +#include #include "cpuemu.h" #ifdef __cplusplus @@ -92,8 +93,8 @@ extern "C" { /* Hardware specifics. */ #define portSTACK_GROWTH ( -1 ) -#define portTICK_RATE_MS ( 1) //( ( portTickType ) 1000 / 15625 ) -#define portMS_TO_TICKS(ms) ( ( portTickType ) (1000*(ms) + (15625)/2)/15625 ) +#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) +#define portTICK_RATE_MICROSECONDS ( ( portTickType ) 1000000 / configTICK_RATE_HZ ) #define portBYTE_ALIGNMENT 4 #define portYIELD() __swi(); @@ -126,8 +127,7 @@ extern void vTaskSwitchContext( void ); \ extern void vPortForciblyEndThread( void *pxTaskToDelete ); #define traceTASK_DELETE( pxTaskToDelete ) vPortForciblyEndThread( pxTaskToDelete ) -extern void vPortAddTaskHandle( void *pxTaskHandle ); -#define traceTASK_CREATE( pxNewTCB ) vPortAddTaskHandle( pxNewTCB ) +#define traceTASK_CREATE( pxNewTCB ) /* Make use of times(man 2) to gather run-time statistics on the tasks. */ extern void vPortFindTicksPerSecond( void );