Skip to content

Latest commit

 

History

History
282 lines (200 loc) · 7.87 KB

File metadata and controls

282 lines (200 loc) · 7.87 KB

ESP8266 PlatformIO Tutorial: From Basics to FreeRTOS

Introduction

Welcome to this hands-on tutorial for getting started with ESP8266 using PlatformIO! We'll cover the basics of setting up your development environment and then dive into a series of challenges to learn about serial communication, GPIO, PWM, and servos. Finally, we'll introduce you to the basics of FreeRTOS.

Setting Up PlatformIO

  1. Install Visual Studio Code (VSCode) from https://code.visualstudio.com/
  2. Open VSCode and go to the Extensions view (Ctrl+Shift+X)
  3. Search for "PlatformIO" and install the PlatformIO IDE extension
  4. Restart VSCode after the installation

Creating Your First Project

  1. Click on the PlatformIO icon in the left sidebar
  2. Choose "New Project"
  3. Name your project "ESP8266_Tutorial"
  4. Select "Espressif ESP8266 ESP-12E" as your board
  5. Choose "Arduino" as your framework
  6. Wait for the project to be created and initialized

Challenge 1: Hello, Serial!

Objective: Print "Hello, ESP8266!" to the serial monitor every second.

  1. Open src/main.cpp
  2. Replace the contents with the following code:
#include <Arduino.h>

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println("Hello, ESP8266!");
  delay(1000);
}
  1. Build and upload the code to your ESP8266
  2. Open the Serial Monitor to see the output

Challenge: Modify the code to print the number of seconds since the ESP8266 started.

Challenge 2: Blinky LED

Objective: Make the built-in LED blink every 500ms.

  1. Modify src/main.cpp:
#include <Arduino.h>

const int LED_PIN = 2;  // Built-in LED on ESP-12E module

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}
  1. Upload and observe the blinking LED

Challenge: Create a morse code function that blinks "SOS" (... --- ...) repeatedly.

Challenge 3: PWM LED Control

Objective: Use PWM to gradually fade the LED in and out.

  1. Update src/main.cpp:
#include <Arduino.h>

const int LED_PIN = 2;

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  for (int i = 0; i <= 255; i++) {
    analogWrite(LED_PIN, i);
    delay(10);
  }
  for (int i = 255; i >= 0; i--) {
    analogWrite(LED_PIN, i);
    delay(10);
  }
}
  1. Upload and observe the fading LED

Challenge: Implement a "breathing" effect by using a sine wave for smoother transitions.

Challenge 4: Servo Control

Objective: Control a servo motor using the ESP8266.

  1. Connect a servo to your ESP8266 (signal wire to GPIO 4, power to 3.3V, ground to GND)
  2. Install the "ESP8266Servo" library from PlatformIO Library Manager
  3. Update src/main.cpp:
#include <Arduino.h>
#include <ESP8266Servo.h>

Servo myservo;
const int SERVO_PIN = 4;

void setup() {
  myservo.attach(SERVO_PIN);
}

void loop() {
  myservo.write(0);
  delay(1000);
  myservo.write(90);
  delay(1000);
  myservo.write(180);
  delay(1000);
}
  1. Upload and watch the servo move

Challenge: Create a function that moves the servo to a random position every 2 seconds.

Introduction to FreeRTOS

FreeRTOS is a real-time operating system that allows you to create tasks that run concurrently. Let's create a simple example using FreeRTOS and explore its key concepts.

  1. Update src/main.cpp:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>

Ticker blinker;
const int LED_PIN = 2;
bool ledState = false;

void blinkLED() {
  ledState = !ledState;
  digitalWrite(LED_PIN, ledState);
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  
  blinker.attach(0.5, blinkLED);  // Blink LED every 500ms
  
  xTaskCreate(
    [](void * parameters) {
      for(;;) {
        Serial.println("Hello from FreeRTOS task!");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    },
    "PrintTask",
    1000,
    NULL,
    1,
    NULL
  );
}

void loop() {
  // The loop function can be empty when using FreeRTOS
}
  1. Upload and observe the LED blinking and serial output

This example demonstrates two concurrent operations:

  • Blinking the LED using the Ticker library
  • Printing a message every second using a FreeRTOS task

Understanding xTaskCreate

The xTaskCreate function is fundamental to FreeRTOS. It's used to create a new task. Let's break down its parameters:

BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,
    const char * const pcName,
    uint16_t usStackDepth,
    void *pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t *pxCreatedTask
);

In our example:

xTaskCreate(
    [](void * parameters) {
        for(;;) {
            Serial.println("Hello from FreeRTOS task!");
            vTaskDelay(1000 / portTICK_PERIOD_MS);
        }
    },
    "PrintTask",
    1000,
    NULL,
    1,
    NULL
);

Let's examine each parameter:

  1. TaskFunction_t pvTaskCode: This is the actual function that will run as a task. We're using a lambda function that prints a message and then delays for 1 second.

  2. const char * const pcName: This is a name for the task, used for debugging. We've named it "PrintTask".

  3. uint16_t usStackDepth: This is the stack size in words. We've allocated 1000 words.

  4. void *pvParameters: These are parameters to pass to the task. We're not using any, so it's NULL.

  5. UBaseType_t uxPriority: This sets the priority of the task. We've set it to 1, which is a low priority.

  6. TaskHandle_t *pxCreatedTask: This is a handle to the created task. We're not storing the handle, so it's NULL.

Basics of the FreeRTOS Scheduler

The FreeRTOS scheduler is responsible for deciding which task should be running at any given time. It uses a priority-based preemptive scheduling algorithm. Here are some key points:

  • Each task is given a priority (in our case, we set it to 1).
  • The scheduler ensures that the highest priority task that is ready to run gets CPU time.
  • Tasks with the same priority are scheduled round-robin (they take turns).
  • Lower priority tasks only run when no higher priority tasks are ready.
  • vTaskDelay() is used to make a task "sleep" for a specified time, allowing other tasks to run.

In our example, we only have one task, so it will run repeatedly, printing the message and then delaying for 1 second.

Understanding blinker.attach

The blinker.attach function is not part of FreeRTOS, but comes from the Ticker library, which is specific to ESP8266. Here's how it's used in our code:

Ticker blinker;
blinker.attach(0.5, blinkLED);

The attach function sets up a function to be called repeatedly at a specified interval. It takes two parameters:

  1. float seconds: The interval in seconds. In our case, it's 0.5 seconds.
  2. callback_t callback: The function to be called. In our case, it's blinkLED.

This setup will cause the blinkLED function to be called every 0.5 seconds, toggling the LED state. This happens independently of the FreeRTOS task we created.

Conclusion

In this example, our program is doing two things concurrently:

  1. Blinking an LED every 0.5 seconds using the Ticker library.
  2. Printing a message every second using a FreeRTOS task.

This demonstrates how we can handle multiple operations on the ESP8266, some using FreeRTOS (like our printing task) and others using platform-specific libraries (like the LED blinking with Ticker).

Next Steps

Now that you understand the basics of FreeRTOS and task creation, try these challenges:

  1. Create a second task that increments a counter and prints its value every 5 seconds.
  2. Modify the LED blinking task to use FreeRTOS instead of the Ticker library.
  3. Implement a simple state machine using FreeRTOS tasks to control multiple LEDs.

Remember, FreeRTOS is a powerful tool for managing concurrent operations on your ESP8266. As you build more complex projects, you'll find it invaluable for organizing your code and managing multiple simultaneous tasks.