Configuring ESP32 to act as Access Point

In a previous article we learned how to use ESP32 as a WiFi client. If you haven’t I recommend you take a look at that article, since there are some steps in common that I’m not going to cover in much depth here.

Initialize WiFi

When we are creating a client or and Access Point, we need to initialize NETIF and create the default event loop:

1
2
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

To initialize our WiFi interface as an Access Point, we need to call:

1
esp_netif_create_default_wifi_ap();
Read More

B-Trees - Database storage internals

Some of the most popular databases out there (PostgreSQL, MySQL, MongoDB, etc) use b-trees for their indexes. In this article, we’re going to learn how they work and understand why they are used.

Files

Before we understand how databases store information, we need to understand how computers store information.

When we want to persist data, we use the file system API. This API allows us to open files for reading, writing or appending. When a file is opened, it’s loaded into memory. Once the data is in memory, we can access bytes sequentially or in any order we desire (Random Access).

Read More

Aligned and packed data in C and C++

I was reading some networking code and I stumbled into something that looked similar to this:

1
2
3
4
5
typedef struct __attribute__((__packed__)) {
  uint8_t a;
  uint16_t b;
  uint32_t c;
} some_t;

I had no idea what __attribute__((__packed__)) meant, so I did some digging and learned a bit about data alignment.

Read More

ESP32 Non-Volatile Storage (NVS)

In this article, we are going to learn how to use NVS to store key-value pairs that persist even if our board is restarted.

What is NVS

NVS stands for Non-Volatile Storage. It’s a library that allows us to store key-value pairs in flash memory.

ESP-IDF projects partition the boards flash into different sections. Among these partitions, there is one where our application code lives and there is another section we can use to store any data we want. This section is called the data partition, and that’s what NVS uses for storage.

Flash models

Different development boards might come with different models of flash memory. I bought a cheap development board from my local electronics shop, and it didn’t include much information about the specs, so I didn’t really know what flash it uses.

Luckily, ESP-IDF comes with a tool we can use to get information about our flash memory:

1
esptool.py --port /dev/ttyUSB0 flash_id

The output for my board included this:

1
2
3
Manufacturer: 5e
Device: 4016
Detected flash size: 4MB
Read More

Making HTTP / HTTPS requests with ESP32

I have in the past written an article explaining how to send HTTP requests with Arduino. This time we’re going to learn how to do it using ESP-IDF.

This article is the result of my learnings from analyzing the official ESP HTTP client example.

ESP-NETIF

ESP-NETIF is ESP32’s abstraction for TCP/IP. It’s not too complicated to use, but it’s somewhat verbose. All applications that use it need to start by calling:

1
esp_netif_init();

This function should be called only once, when the application starts.

Read More

Modularizing ESP32 Software

In my ESP32 journey, I’ve come to a point, where I want to be able to split my code into libraries and consume third-party libraries. In this article, I’m going to explore how to do this.

The project directory tree

ESP32 projects follow a folder structure:

1
2
3
4
5
6
7
8
9
10
11
12
project/
├─ components/
│  ├─ component1/
│  │  ├─ CMakeLists.txt
│  │  ├─ ...
│  ├─ component2/
│     ├─ CMakeLists.txt
│     ├─ ...
├─ main/
│  ├─ CMakeLists.txt
│  ├─ ...
├─ CMakeLists.txt
Read More

Neovim as ESP32 IDE with Clangd LSP

In this article, I’m going to explain how to configure Neovim to work as an IDE for ESP32.

Before we start, we need to have ESP-IDF in our system. You can follow my Introduction to ESP32 development article for instructions on how to install it.

Lazy vim

I use lazy to manage my Neovim plugins, so let’s make sure it’s configured correctly. To do that, we need to add these lines to our init.lua (usually at ~/.config/nvim/init.lua):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    'git',
    'clone',
    '--filter=blob:none',
    'https://github.com/folke/lazy.nvim.git',
    '--branch=stable', -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require('lazy').setup('plugins')
Read More

Introduction to ESP32 development

A few months ago, I started learning Arduino, and recently I finished my first small project. After finishing the project, I was wondering if I could build the same thing for cheaper, and that’s when I stumbled into ESP32.

ESP32 is an MCU (Micro Controller Unit) that got very popular because it has integrated WiFi, Bluetooth, very good documentation and is relatively cheap for what it does. Interestingly, the Arduino UNO R4 WiFi contains two MCU and one of them is an ESP32.

Getting an ESP32

The easiest way to get started with ESP32 is to buy a development board. While you can find some in Espressif’s website (The manufacturer of ESP32), you can also get clones from many places around the world.

I’m currently in Cape Town, so got mine from Communica. I ended up paying $7.50 USD for it. Depending on where you live and how long you are willing to wait to get one, you might be able to get it for considerably cheaper.

ESP32 dev board

Read More

Asynchronous Programming with Tokio

If you are interested in learning about asynchronous programming in more depth, I recommend reading Asynchronous Programming in Rust.

Asynchronous programming

When we run code that makes network requests, these request are sent through the network.

Sending the request and waiting for the response is done by the network peripheral and doesn’t require the CPU. This means, the CPU is free to do other things while it waits.

Code written synchronously will send a request and then block the thread waiting for a response. For example:

1
2
3
4
fn main() {
    let resp = reqwest::blocking::get("https://httpbin.org/ip")?.text()?;
    println!("{:#?}", resp);
}
Read More

Programming Concurrency in Rust

One of Rust’s most praised features is how it makes concurrent programming safe. In this article we are going to learn some ways to do concurrent programming and explain how Rust makes them safe compared to other programming languages.

Working with threads

We can start new threads with thread::spawn:

1
2
3
4
5
6
7
8
9
10
use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        println!("The spawned thread");
    });

    thread::sleep(Duration::from_millis(1));
}

This will print:

1
The spawned thread
Read More