Skip to content

dweggg/scheduler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Scheduler

My dummy simple and fast scheduler for embedded with the features I need.


📋 Requirements

  • A periodic tick source with known frequency (like a hardware timer). You could use DWT/SysTick in a Cortex-M, Core Timer CP0 in PIC32, set up a CPU timer in C28x... A faster tick source will give you the ability to run tasks at higher frequencies.

🖥️ Example: STM32 (ARM Cortex‑M4)

#include "scheduler.h" // don't forget this!

// 1) Enable and zero the DWT cycle counter
static void dwt_init(void) {
    // 1a) Enable trace & debug blocks
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    // 1b) Reset the cycle counter
    DWT->CYCCNT = 0;
    // 1c) Enable the cycle counter
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

// 2) Our tick source function just returns the 32‑bit cycle counter
static uint32_t dwt_get_ticks(void) {
    return DWT->CYCCNT;
}

// 3) Write tasks
uint32_t task_a_freq = 10000; // task a will run at 10kHz, or once every 100us
void task_a(void) {
    // place your code here
}


uint32_t task_b_freq = 200; // task b will run at 200Hz, or once every 5000us
void task_b(void) {
    // place your other code here

}

int main(void) {
    // 4) Initialize DWT
    dwt_init();

    // 5) Initialize scheduler with the tick source
    scheduler_init(
        dwt_get_ticks, // this is the pointer to a function that returns a uint32_t (always increasing counter)
        HAL_RCC_GetSysClockFreq() // this is a uint32_t that indicates the number of ticks generated per second by your tick source
    );

    // 6) Add tasks
    scheduler_add_task(task_a, task_a_freq);
    scheduler_add_task(task_b, task_b_freq);

    // 7) Start the scheduler (never returns)
    scheduler_run();

    // Should never reach here
    while (1) {
  }
}

There's a couple of useful features you can use at runtime:

scheduler_set_task_frequency(task_b, 1000); // now task_b will run at 1kHz

uint32_t task_a_load;
task_a_load = scheduler_get_last_exec_time_us(task_a); // the variable task_a_load will hold the amount of microseconds that took task_a to be completed the last time it ran

scheduler_stop_task(task_a); // task_a will stop running
scheduler_start_task(task_a); // task_a will start running again

uint32_t current_tick;
current_tick = scheduler_get_tick(); // the variable current_tick will hold the current tick of the scheduler at the time of calling the function.

uint8_t cpu;
cpu = scheduler_get_cpu(); // the variable cpu will hold a rough estimate of the current cpu load.

If you need to run tasks slower than 1s you could do something like this:

void task_10s(void){
  // your code here
}
void task_2s(void){
  // your code here
}
uint32_t task_1s_freq = 1; //[Hz]
void task_1s(void) {
  static uint32_t counter_1s = 0;

  if (counter_1s % 10 == 0) {
    task_10s();  // runs every 10 seconds
  }
  if (counter_1s % 2 == 0) {
    task_2s();   // runs every 2 seconds
  }

  counter_1s++;
}

⚠️The scheduler will not work if:

  • You use an infinite loop inside a task
  • A task takes too long to finish and blocks others (it's cooperative, so no preemption means you're responsible for being quick)
  • Code running in ISRs hogs the CPU

📄 License

Do whatever you want.

About

Minimalistic portable scheduler in C

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages