avr-task-scheduler

AVR mcu bare metal task scheduler
Index Commits Files Refs README LICENSE
commit ce1f6db630d608bdf7f0688c839f8b5728894931
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Sat, 27 Sep 2025 23:58:51 -0300

first commit

Diffstat:
AMakefile | 42++++++++++++++++++++++++++++++++++++++++++
Ainclude/scheduler.h | 20++++++++++++++++++++
Ainclude/timer.h | 9+++++++++
Asrc/main.c | 37+++++++++++++++++++++++++++++++++++++
Asrc/scheduler.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/timer.c | 40++++++++++++++++++++++++++++++++++++++++
6 files changed, 193 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,42 @@
+PORT ?= /dev/ttyUSB0
+BIN_DIR = bin
+SRC_DIR = src
+INC_DIR = include
+
+SRCS := $(wildcard $(SRC_DIR)/*.c)
+LIBS := $(INC_DIR/*.h)
+OBJS := $(patsubst $(SRC_DIR)/%.c,$(BIN_DIR)/%.o,$(SRCS))
+
+CC := avr-gcc
+CFLAGS := -Wall -Os -DF_CPU=16000000UL -mmcu=atmega328p -I ./$(INC_DIR)
+
+.PHONY: all
+
+all: $(BIN_DIR) compile
+
+$(BIN_DIR)/%.o: $(SRC_DIR)/%.c
+    $(CC) $(CFLAGS) \
+        -c $< -o $@
+    @echo ""
+
+compile: $(OBJS)
+    $(CC) $(CFLAGS) \
+        -o $(BIN_DIR)/main.elf $(OBJS)
+    @echo ""
+    avr-objcopy -O ihex -R .eeprom $(BIN_DIR)/main.elf $(BIN_DIR)/main.hex
+
+upload: compile
+    avrdude -F -V -c arduino -p ATMEGA328P \
+        -P $(PORT) -b 115200 -U flash:w:$(BIN_DIR)/main.hex
+
+$(BIN_DIR):
+    @if [ ! -d "$(BIN_DIR)" ]; then          \
+        echo "Creating folder '$(BIN_DIR)'"; \
+        mkdir -p $(BIN_DIR);                 \
+    fi
+
+size:
+    avr-size --format=avr --mcu=atmega328p $(BIN_DIR)/main.elf
+
+clean:
+    rm -rf $(BIN_DIR)
diff --git a/include/scheduler.h b/include/scheduler.h
@@ -0,0 +1,20 @@
+#ifndef _SCHEDULER_H_
+#define _SCHEDULER_H_
+
+#define SCHEDULER_MAX_TASKS_CNT 10
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+void scheduler_init(void);
+void scheduler_update(void);
+void scheduler_append_task(void (*update_func)(void), uint16_t update_interval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SCHEDULER_H_
diff --git a/include/timer.h b/include/timer.h
@@ -0,0 +1,9 @@
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include <stdint.h>
+
+void timer_init(void);
+void timer_add_callback(void (*func_ptr)(void));
+
+#endif // _TIMER_H_
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,37 @@
+#include <avr/io.h>
+
+#include "timer.h"
+#include "scheduler.h"
+
+#define LED_1_PIN  3
+#define LED_2_PIN  4
+
+void toggle_led_1(void) {
+    PIND = (1 << LED_1_PIN);
+}
+
+void toggle_led_2(void) {
+    PIND = (1 << LED_2_PIN);
+}
+
+void setup(void) {
+    DDRD |= (1 << LED_1_PIN) | (1 << LED_2_PIN);
+
+    scheduler_init(tasks, tasks_cnt);
+
+    // scheduler_append_task(&toggle_led_1, 1000);
+    // scheduler_append_task(&toggle_led_2, 500);
+
+    timer_init();
+    timer_add_callback(&scheduler_update);
+}
+
+int main(void) {
+    setup();
+
+    while(1) {
+        ;;
+    }
+
+    return 0;
+}
diff --git a/src/scheduler.c b/src/scheduler.c
@@ -0,0 +1,45 @@
+#include "scheduler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    void (*task_update)(void);
+    uint16_t update_interval;
+    uint16_t ticks;
+} task_t;
+
+typedef struct {
+    uint8_t task_cnt;
+    task_t tasks[SCHEDULER_MAX_TASKS_CNT];
+} scheduler_t;
+
+static scheduler_t scheduler = {0};
+
+void scheduler_init(void) {
+    scheduler.task_cnt = 0;
+}
+
+// should be called exactly every ms
+void scheduler_update(void) {
+    for (uint8_t i = 0; i < scheduler.task_cnt; ++i) {
+        if (scheduler.tasks[i].ticks > 0) {
+            scheduler.tasks[i].ticks--;
+            continue;
+        }
+
+        scheduler.tasks[i].ticks = scheduler.tasks[i].update_interval;
+        scheduler.tasks[i].task_update();
+    }
+}
+
+void scheduler_append_task(void (*update_func)(void), uint16_t update_interval) {
+    scheduler.tasks[scheduler.task_cnt].task_update = update_func;
+    scheduler.tasks[scheduler.task_cnt].update_interval = update_interval - 1;
+    scheduler.task_cnt++;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/timer.c b/src/timer.c
@@ -0,0 +1,40 @@
+#include "timer.h"
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#define TIMER_CALLBACKS_MAX_CNT 1
+
+typedef struct {
+    uint8_t callbacks_cnt;
+    void (*callbacks[TIMER_CALLBACKS_MAX_CNT])(void);
+} timer_t;
+
+static timer_t timer = {0};
+
+ISR(TIMER0_COMPA_vect) {
+    for(uint8_t i = 0; i < timer.callbacks_cnt; ++i) {
+        timer.callbacks[i]();
+    }
+}
+
+// normal mode, prescaler 64, max value 250 == exact 1 interrupt per ms
+void timer_init(void) {
+    cli();
+    TCCR0A = (1 << WGM01) | (1 << COM0A0);
+    TCCR0B = (1 << CS01) | (1 << CS00);
+    TIMSK0 = (1 << OCIE0A);
+    OCR0A = 250;
+    sei();
+
+    // timer_add_callback(&timer_increment_millis);
+}
+
+void timer_add_callback(void (*callback)(void)) {
+    if (timer.callbacks_cnt == TIMER_CALLBACKS_MAX_CNT) {
+        return;
+    }
+
+    timer.callbacks[timer.callbacks_cnt] = callback;
+    timer.callbacks_cnt++;
+}