Click here to Skip to main content
15,887,027 members
Home / Discussions / C / C++ / MFC
   

C / C++ / MFC

 
Questioncreate_task function in PPL Pin
Daniel Ramnath11-Jun-18 7:29
Daniel Ramnath11-Jun-18 7:29 
QuestionRe: create_task function in PPL Pin
David Crow11-Jun-18 9:54
David Crow11-Jun-18 9:54 
AnswerRe: create_task function in PPL Pin
Daniel Ramnath11-Jun-18 20:36
Daniel Ramnath11-Jun-18 20:36 
AnswerRe: create_task function in PPL Pin
Daniel Ramnath11-Jun-18 20:30
Daniel Ramnath11-Jun-18 20:30 
QuestionDynamic programming fill 3D array Pin
pro grimi10-Jun-18 23:12
pro grimi10-Jun-18 23:12 
QuestionInitInstance() implimentation. Pin
Member 1271142610-Jun-18 20:17
Member 1271142610-Jun-18 20:17 
AnswerRe: InitInstance() implimentation. Pin
Jochen Arndt10-Jun-18 21:24
professionalJochen Arndt10-Jun-18 21:24 
QuestionAdvice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
arnold_w9-Jun-18 10:37
arnold_w9-Jun-18 10:37 
I am working on an embedded product with an ARM-processor and I need to come up with an approach on how scheduling of tasks is going to work and then implement it. The following requirements apply:
• Standard C (no assembler).
• Can run on "any" microcontroller (of course, it needs to have a certain amount of RAM and flash).
• No use of malloc.
• If running on ARM and there's nothing to do and all timers are turned off, then it should enter stop mode (=system clock is turned off).
• If running on ARM and there's nothing to do but at least one timer is running, then it should enter sleep mode (=some peripherals are turned off, but the system clock and timers are still working).
• Needs to have some sort of prioritization, for example, low-level driver tasks needs to be handled before higher level tasks (such as tasks that arisen due to, for example, a push button pressed event) may be handled.
• It needs to, in some way, support calling of asynchronous functions, such as starting a DMA-transfer and then you get an interrupt when it's finished and in between it should execute other tasks.  


My project is fairly limited in scope (not a lot things going on simultaneously), but I'm still struggling a bit to meet all the requirements. I will share below some of my thoughts. I was thinking of something like a modified round-robin scheduler with priorities with a number of queues:
C++
void (*taskFunctionPtr_t)(uint32_t arg1, uint32_t arg2)
enum queueSelector_e {LOW_LEVEL_DRIVERS, USER_EVENTS}; 
addTaskToQueue(taskFunctionPtr_t, queueSelector_e);

In main.c:
C++
while (TRUE) {
    if (0 < numQueuedTasks(LOW_LEVEL_DRIVERS)) {
        handleTask(LOW_LEVEL_DRIVERS);
        continue;
    }
    if (0 < numQueuedTasks(USER_EVENTS)) {
        handleTask(USER_EVENTS);
        continue;
    }
    if (anyTimerRunning()) {
        enterIdleMode();  // System clock is still running, but some peripherals (not the timers!) are turned off
    } else {
        enterStopMode();  // System clock is turned off and can only be woken up user event (external int)
    }
}

In order to support asynchronous tasks, I probably need to make my tasks and queues more advanced:
C++
void (*asynchronousTaskFinishedFunctionPtr)(asynchronousTaskResult_e);
void someAsynchronousFunction(asynchronousTaskFinishedFunctionPtr); 
enum asyncTaskStatus_e {TASK_NOT_STARTED, TASK_IN_WAIT_PHASE, TASK_FINISHED_NEEDS_REPEAT_DUE_TO_ERROR, TASK_SUCCESSFULLY_FINISHED}; 
asyncTaskStatus_e (*getAsyncTaskStatusPtr)();
addSynchronousTaskToQueue(taskFunctionPtr_t, queueSelector_e);
addAsynchronousTaskToQueue(taskFunctionPtr_t, queueSelector_e, getAsyncTaskStatusPtr);

Then I'd have to have something like this in main.c:
C++
while (TRUE) {
    Bool_t taskIsInWaitPhase;
    if (0 < numQueuedTasks(LOW_LEVEL_DRIVERS)) {
        taskIsInWaitPhase = handleTask(LOW_LEVEL_DRIVERS);
        if (!taskIsInWaitPhase) {
            continue;
        }
    }
    if (0 < numQueuedTasks(USER_EVENTS)) {
        taskIsInWaitPhase = handleTask(USER_EVENTS);
        if (!taskIsInWaitPhase) {
            continue;
        }
    }
    if (anyTimerRunning() || atLeastOneTaskInWaitPhase()) {
        enterIdleMode();  // System clock is still running, but some peripherals (not the timers!) are turned off
    } else {
        enterStopMode();  // System clock is turned off and can only be woken up user event (external int)
    }
}

// Returns whether the current task is in wait phase or not
Bool_t handleTask(queueSelector_e) {
    if (taskIsAsynchronous()) {
        if (asynchronousTaskStatus == TASK_SUCCESSFULLY_FINISHED) {
            incrementTaskQueueReadPointer();
        } else if ((asynchronousTaskStatus == TASK_NOT_STARTED) || 
                   (asynchronousTaskStatus == TASK_FINISHED_NEEDS_REPEAT_DUE_TO_ERROR)) {
            callTaskFunction();
        } else if (asynchronousTaskStatus == TASK_IN_WAIT_PHASE) {
            // Do nothing
            return TRUE; 
        }
    } else {
        callTaskFunction();
        incrementTaskQueueReadPointer();
    }
    return FALSE;
}

There are still issues with this approach, for example, how do I handle long tasks? I don't want a driver task to have to wait for a long user task to finish. I guess I need to have a requirement that all tasks need to be short and if they are long in reality, then they need to broken up and then the task will need to tell scheduler to repeat the same task:

C++
void longTask(uint32_t arg1, uint32_t arg2) {
    enum partSelector_e {
       PART1,
       PART2,
       PART3,
       PART4,
       PART5
    };
    static partSelector_e partSelector = PART1;
    switch (partSelector) {
        case PART1: 
            do1stPartOfLongTask();
            partSelector++;
            repeatThisTask();  // Tell scheduler to repeat this task (scheduler will not increment task queue read ptr)
            return;
        case PART1: 
            do2ndPartOfLongTask();
            partSelector++;
            repeatThisTask();  // Tell scheduler to repeat this task (scheduler will not increment task queue read ptr)
            return;
        case PART3: 
            do3rdPartOfLongTask();
            partSelector++;
            repeatThisTask();  // Tell scheduler to repeat this task (scheduler will not increment task queue read ptr)
            return;
        case PART4: 
            do4thPartOfLongTask();
            partSelector++;
            repeatThisTask();  // Tell scheduler to repeat this task (scheduler will not increment task queue read ptr)
            return;
        case PART5: 
            do5thPartOfLongTask();
            partSelector = PART1;
            return;
    }
}


Another problem is how asynchronuous calls can be handled. Let's say I want to do the following and the order of sequence is important:
C++
// This is a task, not an interrupt handler (in the interrupt handler, the following function was added to the USER_EVENTS queue)
void button1pressedTask(uint32_t arg1, uint32_t arg2) {
    readADC();         // Synchronous call, no problem
    setPinHigh();      // Synchronous call, no problem
    startDMAtransfer   // Asynchronous call, MAJOR PROBLEMS!!!! Scheduler needs to able to handle higher priority tasks here!
    writeI2Cdata();    // Synchronous call, no problem
    writeUARTdata();   // Synchronous call, no problem
}


Remember, when calling an asynchronous function, other tasks should be allowed to execute. Does anybody have any suggestions how I can solve this? Am I on the right track or would someone suggest a completely different approach?

modified 10-Jun-18 13:47pm.

AnswerRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
leon de boer10-Jun-18 17:27
leon de boer10-Jun-18 17:27 
GeneralRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
arnold_w10-Jun-18 20:16
arnold_w10-Jun-18 20:16 
GeneralRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
leon de boer11-Jun-18 2:52
leon de boer11-Jun-18 2:52 
GeneralRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
arnold_w11-Jun-18 3:13
arnold_w11-Jun-18 3:13 
GeneralRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
leon de boer11-Jun-18 4:04
leon de boer11-Jun-18 4:04 
GeneralRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
arnold_w11-Jun-18 9:38
arnold_w11-Jun-18 9:38 
AnswerRe: Advice on designing a simple task scheduler in embedded C, that can handle asynchronuous tasks? Pin
supercat920-Jun-18 12:22
supercat920-Jun-18 12:22 
QuestionC# combo box text color change Pin
czaar9998-Jun-18 7:18
czaar9998-Jun-18 7:18 
AnswerRe: C# combo box text color change Pin
Richard Andrew x648-Jun-18 10:54
professionalRichard Andrew x648-Jun-18 10:54 
Questionusing dynamic_cast with template classes. Pin
Tarun Jha5-Jun-18 1:48
Tarun Jha5-Jun-18 1:48 
AnswerRe: using dynamic_cast with template classes. Pin
Richard MacCutchan5-Jun-18 3:20
mveRichard MacCutchan5-Jun-18 3:20 
GeneralRe: using dynamic_cast with template classes. Pin
Tarun Jha5-Jun-18 8:31
Tarun Jha5-Jun-18 8:31 
GeneralRe: using dynamic_cast with template classes. Pin
Richard MacCutchan5-Jun-18 21:00
mveRichard MacCutchan5-Jun-18 21:00 
AnswerRe: using dynamic_cast with template classes. Pin
CPallini5-Jun-18 11:03
mveCPallini5-Jun-18 11:03 
GeneralRe: using dynamic_cast with template classes. Pin
Tarun Jha5-Jun-18 18:45
Tarun Jha5-Jun-18 18:45 
GeneralRe: using dynamic_cast with template classes. Pin
CPallini5-Jun-18 21:22
mveCPallini5-Jun-18 21:22 
GeneralRe: using dynamic_cast with template classes. Pin
Tarun Jha6-Jun-18 3:11
Tarun Jha6-Jun-18 3:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.