mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-29 14:52:12 +01:00
PiOS/Win32: Most stable version of port.c so far. Changed Makefile.win32 to use mingw32-gcc to avoid conflicts.
git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1278 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
parent
e3fb3f3e1b
commit
c1cf1ec71b
@ -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
|
||||
|
||||
|
@ -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 ) )
|
||||
|
@ -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<<CPU_INTR_TICK);
|
||||
SetEvent(hIsrInvoke);
|
||||
@ -229,7 +247,6 @@ static DWORD WINAPI tick_generator(LPVOID lpParameter)
|
||||
// overruns).
|
||||
SignalObjectAndWait(hIsrMutex, hTickAck, INFINITE, FALSE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI TaskSimThread( LPVOID lpParameter )
|
||||
@ -259,20 +276,26 @@ static void create_system_objects(void)
|
||||
hIsrInvoke = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
hTickAck = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
hTermAck = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
#if defined(DEBUG_OUTPUT) || defined(ERROR_OUTPUT)
|
||||
hPrintfMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
#endif
|
||||
|
||||
dwEnabledIsr |= (1<<CPU_INTR_TICK);
|
||||
|
||||
//Set timer
|
||||
|
||||
TIMECAPS tc;
|
||||
timeGetDevCaps(&tc, sizeof(tc));
|
||||
msPerTick = tc.wPeriodMin;
|
||||
debug_printf("Ms per tick: %i\n", msPerTick);
|
||||
if(msPerTick > 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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#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 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user