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
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.
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.)