Skip to content

STM8-Multi-Tasker - Preemptive/Cooperative Round Robin Scheduler for STM8

License

Notifications You must be signed in to change notification settings

vsch/stm8-multi-tasker

Repository files navigation

STM8-Multi-Tasker

Cooperative/Preemptive Round Robin Scheduler for STM8

Stability: Not Ready In Development

Status: Broken Do Not Use Yet

Version: 0.0

A tiny scheduler to allow threading with stack based context switching to be used on the STM8 micro processor. Implemented with SDCC in mixed C and assembler. Using CMake with JetBrains CLion IDE. (TODO: Add Instructions on how to set it up to work reasonably well).

The core is written in assembler to reduce size. The SDCC compiler does not produce very efficient code for the STM8. I opted out to optimize reusable code, then I can use C for specific projects with less concern for space.

With All features enabled, clocks in just over 1k of code, 34 bytes data + per task data use of 8 bytes + task's stack size.

Multi Threading Caveats

Any non re-entrant functions that are called with interrupts enabled will need to be protected from having one task's call interrupted and then another task making the call from another context. There are two ways of handling this:

  • Guard these functions with a Mutex to prevent other tasks from entering until the last task leaves.

  • If the location where the function/library stores its temp variables or global state is known and extra stack space available, then you can use the global state preserving option OPT_PRESERVE_GLOBAL_STATE, write two functions to save state to stack and restore state from stack. These will be called whenever there is a task switch. Use sparingly because the extra space on the stack will need to be allocated for every task and done on every task switch.

  • Use a mix of above methods as needed.

  • Use only cooperative scheduling and don't try to use shared, unlocked resources from ISRs

Library Limitations

  • all assembly routines are written for default SDCC compilation of caller saving registers.
  • Interrupts are disabled while in library calls. This will increased interrupt response latency.

On the plus side, I was using this scheduler design on a Z80 running at a whopping 1MHz. Having a real context switcher to simplify logic and implementation was well worth the overhead.

Usage Examples

  • Cooperative
  • Simple Timer
  • Periodic Timer, adjusted
  • Mutex around lib calls
  • Preserve Global State
  • Events and interrupts

Features

  • Circular linked list queues and nodes. Lists and nodes are interchangeable. An empty queue is one linked to itself, just like an unlinked node. Head of queue is the next pointer, tail is the previous pointer.

    • Initialize node
    • Unlink node
    • Link after next/previous node or head/tail of a list. Will unlink the node before linking it into a new list.
    • Test if node is unlinked or list is empty.

    All elements in the library are QLists or QNodes.

  • Scheduler, implements round robin cooperative scheduling or optionally with preemptive capability when a task exceeds maximum time slice in timer ticks.

    • Yield to relinquish CPU, or on time slice max (if preemptive option is enabled)
    • Global state save/restore via user provided functions to push/pop global state on task switch
  • Timers implement timed waits to resume a task after delay.

    • WaitTicks - suspend for up to 65535 timer ticks before resuming, tick period defined by timer ISR calls.
    • WaitTicksAdj - suspend for up to 65535 timer ticks before resuming. Adjusts requested ticks to compensate for scheduling delay incurred during last resume from a WaitTicks or WaitTicksAdj.
    • WaitMillis - suspend for up to 65535 ms, 65.535 secs
    • WaitSecs - suspend for up to 65535 s, 18hrs 12min 15sec before rescheduling
  • Semaphores implement time allocation of limited resources. Semaphore starts off with initial count of available resources. Every acquisition decrements the count by one, release increments it by one. A task trying to acquire a semaphore will suspend until at least one resource is free.

    • Initialize semaphore passing in initial resource count
    • Acquire semaphore - get single count of resource or suspend until available
    • Release semaphore - release single count of resource
  • Events implement multiple tasks waiting on event, with all tasks resumed when the event is raised.

    • Wait for event - suspend until the next event signal
    • Signal an event - resume all tasks waiting for the event
  • Mutexes same as a single count semaphore but allows the owner task to call lock multiple times without suspending. Unlock must be called equal number of times that lock was called to fully relinquish the mutex. Max lock count is 256.

    • Lock mutex - get ownership of mutex, increment its lock count or suspend until mutex is free.
    • Unlock mutex - decrement lock count, if becomes unlocked then relinquish ownership. Ownership will be given to first task suspended by lock mutex request.

Per Module Resource Requirements

Module Functionality Provided Data (bytes) Code (bytes) Per Instance Overhead (bytes)
Initialization required 4 121
Queues Circular linked lists 0 131 per Node or List: 4
Tasks Cooperative/Preemptive multi-tasking 10 186 per Task: 6 + task stack size
Timers Timed wait, tick, millisec and seconds 24 378 per Task: 2
Semaphores Resource lock Acquire/Release 0 55 per Semaphore: 5
Events Multi task event synchronization 0 60 per Event: 4
Mutexes Multi task lock synchronization 0 121 per Mutex: 7
All All options enabled 38 1052

About

STM8-Multi-Tasker - Preemptive/Cooperative Round Robin Scheduler for STM8

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published