Chapter 2: Starting from Bare Metal#

Sample code#

  • Directory: docs/os-on-arduino/code/02_baremetal

uv run pio run -d 02_baremetal -t upload
uv run pio device monitor -b 115200

Source code#

The sketch for this chapter. Click a file name to expand. The code is mirrored automatically from the manuscript repository, so what you see here is always current.

src/main.cpp — 119 lines

Open on GitHub

  1/**
  2 * Chapter 2: Cooperative Multitasking Scheduler
  3 *
  4 * Demonstrates cooperative (non-preemptive) multitasking.
  5 * Each task runs to completion before another task can run.
  6 *
  7 * Problem: If one task takes too long (like heavy_task),
  8 * all other tasks are delayed.
  9 */
 10
 11#include <Arduino.h>
 12
 13#define LED_PIN LED_BUILTIN
 14#define SERVO_PIN 9
 15
 16// --- Scheduler Definition ---
 17typedef void (*TaskFunc)(void);
 18
 19struct Task {
 20    TaskFunc func;
 21    unsigned long interval;
 22    unsigned long last_run;
 23    const char* name;
 24};
 25
 26#define MAX_TASKS 4
 27Task tasks[MAX_TASKS];
 28int task_count = 0;
 29
 30void scheduler_add_task(TaskFunc func, unsigned long interval, const char* name)
 31{
 32    if (task_count < MAX_TASKS) {
 33        tasks[task_count].func = func;
 34        tasks[task_count].interval = interval;
 35        tasks[task_count].last_run = 0;
 36        tasks[task_count].name = name;
 37        task_count++;
 38    }
 39}
 40
 41void scheduler_run(void)
 42{
 43    unsigned long now = millis();
 44    for (int i = 0; i < task_count; i++) {
 45        if (now - tasks[i].last_run >= tasks[i].interval) {
 46            tasks[i].last_run = now;
 47
 48            Serial.print("[");
 49            Serial.print(now);
 50            Serial.print("ms] Running: ");
 51            Serial.println(tasks[i].name);
 52
 53            tasks[i].func();
 54        }
 55    }
 56}
 57
 58// --- Task Definitions ---
 59void led_task(void)
 60{
 61    static bool state = false;
 62    state = !state;
 63    digitalWrite(LED_PIN, state);
 64    Serial.println("  LED toggled");
 65}
 66
 67void servo_task(void)
 68{
 69    static int angle = 0;
 70    angle = (angle + 10) % 180;
 71    Serial.print("  Servo angle: ");
 72    Serial.println(angle);
 73}
 74
 75void sensor_task(void)
 76{
 77    int value = analogRead(A0);
 78    Serial.print("  Sensor value: ");
 79    Serial.println(value);
 80}
 81
 82void heavy_task(void)
 83{
 84    // Simulate heavy processing
 85    Serial.println("  Heavy task start...");
 86    delay(200);  // 200ms blocking!
 87    Serial.println("  Heavy task end");
 88}
 89
 90// --- Setup and Loop ---
 91void setup()
 92{
 93    Serial.begin(115200);
 94    while (!Serial) { }
 95
 96    pinMode(LED_PIN, OUTPUT);
 97    pinMode(SERVO_PIN, OUTPUT);
 98
 99    Serial.println("=== Cooperative Scheduler Demo ===");
100    Serial.println();
101    Serial.println("This demonstrates cooperative multitasking.");
102    Serial.println("Uncomment heavy_task to see the problem with blocking tasks.");
103    Serial.println();
104
105    // Register tasks
106    scheduler_add_task(led_task, 500, "LED");
107    scheduler_add_task(servo_task, 100, "Servo");
108    scheduler_add_task(sensor_task, 200, "Sensor");
109    // Uncomment the following line to see the problem:
110    // scheduler_add_task(heavy_task, 1000, "Heavy");
111
112    Serial.println("Tasks registered. Starting scheduler...");
113    Serial.println();
114}
115
116void loop()
117{
118    scheduler_run();
119}

On the board#

The Servo task only computes an angle and prints it; it sends no signal to a servo, so you do not need to connect one.

../_images/ch02_tasks.gif

Servo angle moves 10 degrees at a time, with LED and Sensor in between: the three tasks take turns.#

Pitfalls#

(Collected from reader questions — ask via GitHub Issues.)