Getting the OS
Download the latest release from the official repository :
QuarkTS Releases
Unpack the release package and add the sources files to your project.
Cloning QuarkTS
You only need to clone the kernel
branch as follows:
git clone -b kernel https://github.com/kmilo17pet/QuarkTS.git
Including QuarkTS as a git sub-module
Add the OS kernel as a submodule to your project:
git submodule add -b kernel https://github.com/kmilo17pet/QuarkTS.git <destination path>
Then, run the initialize command to fetch the code for the first time:
git submodule update --init
To update the submodule to the latest just run:
git submodule update --remote
Get a copy of the OS configuration file
The file qconfig.h
provides specific Configuration macros to customize several aspects of the OS. In order to build your solution with QuarkTS, you should provided your own copy of this configuration file. You can obtain a copy with the default configuration by issuing the following command:
curl https://raw.githubusercontent.com/kmilo17pet/QuarkTS/master/src/config/qconfig.h -o <destination path>/qconfig.h
First steps
Include the source files to your project. Also, make sure you add a copy of the file qconfig.h
and modify it according to your needs. Setup your compiler including the path of the OS directory. Include the header file QuarkTS.h
and setup the instance of the kernel using the qOS_Setup() inside the main thread to initialize te kernel, specify the reference clock and the idle-task ( see Timing Approach). Additional configuration to the target compiler may be required to add the path to the directory of header files. The code below shows a common initialization procedure in the main source file.
File main.c
#include "QuarkTS.h"
#define TIMER_TICK ( 0.001f )
void main( void ) {
HardwareSetup();
Configure_Periodic_Timer_Interrupt_1ms();
qOS_Setup( NULL , TIMER_TICK , IdleTask_Callback );
}
qBool_t qOS_Setup(const qGetTickFcn_t tFcn, const qTimingBase_t t, qTaskFcn_t idleCallback)
Task Scheduler Setup. This function is required and must be called once in the application main threa...
Definition qkernel.c:126
In the above code, the following considerations should be taken:
- The function qOS_Setup() must be called before any interaction with the OS.
- The procedure
HardwareSetup()
should be a function with all the hardware instructions needed to initialize the target system.
- The procedure
Configure_Periodic_Timer_Interrupt_1ms()
should be a function with all the hardware instructions needed to initialize and enable a timer with an overflow tick of one millisecond.
Tasks can be later added to the scheduling scheme by simply calling qOS_Add_Task() or any of the other available APIs for specific purpose tasks.
Two simple demonstrative examples
A simple scheduling
This example demonstrates a simple environment setup for multiple tasks. Initially, only task1
and task2
are enabled. task1
runs every 2 seconds 10 times and then stops. task2
runs every 3 seconds indefinitely. task1
enables task3
at its first run. task3
run every 5 seconds. task1
disables task3
on its last iteration and change task2
to run every 1/2 seconds. In the end, task2
is the only task running every 1/2 seconds.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "BSP.h"
#include "QuarkTS.h"
#define TIMER_TICK ( 0.001f )
void interrupt Timer0_ISR( void ) {
}
BSP_UART1_WriteString( "Task1" );
}
}
}
BSP_UART1_WriteString( "Task2" );
}
BSP_UART1_WriteString( "Task3" );
}
int main( void ) {
HardwareSetup();
Configure_Periodic_Timer0_Interrupt_1ms();
return 0;
}
void qClock_SysTick(void)
Feed the system tick.
Definition qclock.c:94
qBool_t qOS_Add_Task(qTask_t *const Task, qTaskFcn_t callbackFcn, const qPriority_t p, const qTime_t t, const qIteration_t n, const qState_t init, void *arg)
Add a task to the scheduling scheme. The task is scheduled to run every t seconds,...
Definition qkernel.c:416
qBool_t qOS_Run(void)
Executes the scheduling scheme. It must be called once after the task pool has been defined.
Definition qkernel.c:686
#define qPeriodic
A directive indicating that the task will run every time its timeout has expired.
Definition qkernel.h:80
#define qTask_Suspend(Task)
Put the task into a disabled state.
Definition qtasks.h:533
qBool_t qTask_Set_Time(qTask_t *const Task, const qTime_t tValue)
Set/Change the Task execution interval.
Definition qtasks.c:95
#define qTask_Resume(Task)
Put the task into an enabled state.
Definition qtasks.h:549
#define qEnabled
A state value that enables a task.
Definition qtypes.h:167
#define qDisabled
A state value that disables a task.
Definition qtypes.h:172
The task argument with all the regarding information of the task execution.
Definition qtasks.h:162
qBool_t FirstIteration
Indicates whether current pass is the first iteration of the task. This flag will be only set when ti...
Definition qtasks.h:193
qBool_t LastIteration
Indicates whether current pass is the last iteration of the task. This flag will be only set when tim...
Definition qtasks.h:201
A task node object.
Definition qtasks.h:268
Using the task argument
When adding tasks, they can accept a parameter of type pointer to void void*
also called the storage pointer. This parameter could be used for multiple applications, including storage, task identification, duplication removal and others. The following example shows the usage of this argument to avoid callback duplication among tasks with the same behavior.
Consider a scenario where you have to build a digital controller for several physical variables, for example, a PID controller for temperature, humidity and light. The PID algorithm will be the same for all variables. The only difference will be the variable input, the controlled output action and the PID gains. In this case, each of the PID tasks will utilize the same callback methods. The only difference will be the I/O parameters (specific for each PID controller).
Let’s define a PID data structure with the I/O variables and gains.
typedef struct {
float yt;
float ut;
float ie;
float pe;
float dt;
float sp;
float Kc, Ki, Kd;
} PID_Params_t;
PID_Params_t TemperatureControl = {
0.0f, 0.0f, 0.0f, 0.0f,
1.5f,
28.5f,
0.89f, 0.122f, 0.001f
};
PID_Params_t HumidityControl= {
0.0f, 0.0f, 0.0f, 0.0f,
1.0f,
60.0f,
2.5f, 0.2354f, 0.0015f
};
PID_Params_t LightControl= {
0.0f, 0.0f, 0.0f, 0.0f,
0.5f,
45.0f,
5.36f, 0.0891f, 0.0f
};
A task will be added to the scheme to collect the sensor data and apply the respective control output.
#define qMedium_Priority
A macro directive to indicate the medium priority level.
Definition qkernel.h:74
TemperatureControl.yt = SampleTemperatureSensor();
HumidityControl.yt = SampleHumiditySensor();
LightControl.yt = SampleLightSensor();
WriteTemperatureActuatorValue( TemperatureControl.ut );
WriteHumidityActuatorValue( HumidityControl.ut );
WriteLightActuatorValue( LightControl.ut );
}
Then, three different tasks are created to apply the respective PID controller. Note that these tasks refer to the same callback method and we assign pointers to the respective variables.
qOS_Add_Task( &TEMPERATURE_CONTROL_TASK, PIDControl_Callback,
#define qHigh_Priority
A macro directive to indicate the highest priority level.
Definition qkernel.h:77
void PIDControl_Callback(
qEvent_t e ) {
float Error, derivative;
PID_Params_t *Controller = (PID_Params_t *)e->
TaskData;
Error = Controller->sp - Controller->yt;
Controller->ie += Error*Controller->dt;
derivative = ( Error - Controller->pe )/Controller->dt;
Controller->pe = Error;
Controller->ut = Controller->Kc*Error + Controller->Ki*Controller->ie + Controller->Kd*derivative;
}
void * TaskData
Task arguments defined at the time of its creation. (Storage-Pointer)
Definition qtasks.h:167