Ultra Low-powered Linux Computer using MCU

A portable computer that runs on a Linux operating system can fit in your pocket.

Public Chat
Similar projects worth following
We are going to build a small, functional and ultra low-powered Linux computer using mostly stackable hardware components. The Arduino Nano ESP32 with an ESP32S3 microcontroller (512 KB SRAM and 8 MB PSRAM) will run the Linux operating system.

Linux is a family of open-source operating systems that are based on the Linux kernel, which is a core program that manages the communication between hardware and software. Linux was created by Linus Torvalds in 1991 and has since grown to become one of the most widely used and versatile operating systems in the world.

One of the main advantages of Linux is its portability, which means that it can run on different types of hardware platforms, such as personal computers, servers, smartphones, tablets, embedded devices, and supercomputers. Linux can also be customized and modified according to the needs and preferences of the users and developers, as it is distributed under a free and open-source license. This allows for great diversity and innovation in the Linux ecosystem, with many different distributions and applications available for various purposes and audiences.

Linux port on microcontrollers is the process of running Linux applications on embedded devices that use microcontroller units (MCUs) instead of microprocessor units (MPUs). MCUs are typically cheaper, smaller, and more power-efficient than MPUs, but they have less memory and processing power, and they do not support memory management units (MMUs) that are required by most Linux distributions.

This project is based on the work of  jcmvbkbc, who has ported Linux to various Xtensa platforms.

  • 1 × Arduino Nano ESP32
  • 1 × Arduino UNO R4 WiFi
  • 1 × CardKB Mini Keyboard Programmable Unit
  • 1 × ArduEZ One Stackable Breadboard
  • 1 × Adafruit 2.8" TFT Touch Shield for Arduino with Capacitive Touch

View all 6 components

  • 1
    Build Linux and flash to the Arduino Nano ESP32

    We would need another Linux machine (or a Linux VM) to cross-compile and build the kernels and filesystems. I am using a Ubuntu 22.04 Linux machine. Please execute the commands below to install prerequisites. 

    $ sudo apt install git wget flex bison gperf python3 python3-pip python3-venv   
    $ sudo apt install cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0  

    Download the script from here and execute it to build the Linux for the ESP32S3 target. This script automates compiling and flashing firmware and Linux to Arduino Nano ESP32. 

    $ bash 

    After flashing the board successfully and resetting or power cycling the board. we can see the boot-up console messages by connecting a USB-to-Serial adapter to the Nano ESP32's UART pins (TX0/RX0). But later in this project we will connect the Nano ESP32 to the UNO R4 WiFi via serial connection to emulate the command line terminal console.  

  • 2
    Setup hardware

    In order to construct a computer, we require the hardware components depicted in the image. 

    We are using an ArduinoEZ ONE stackable breadboard shield to connect the Nano ESP32 to the UNO R4 Wi-Fi via a serial connection, as demonstrated in the image below.

    The pins are connected as follows.

    UNO R4 WiFi                  Nano ESP32 
     RX0                                 TX1 
     TX1                                  RX0 
     5V                                   VIN 
     GND                               GND

    We are using an M5Stack CardKB, a tiny full QWERTY keyboard, connected to the Uno R4 WiFi via onboard Qwiic connector over I2C. 

    Once all the components have been assembled and stacked, the computer should look like the image below. 

    This design does not require soldering and is convenient to use. 

  • 3
    Build and Flash Uno R4 WiFi Firmware

    The Arduino Uno R4 WiFi is used to drive an Adafruit TFT display and communicate to the Nano ESP32 over a serial connection. The complete sketch is given below. 

    #include <Wire.h>  
    #include "SPI.h"  
    #include "Adafruit_GFX.h"  
    #include "Adafruit_ILI9341.h"  
    #define CARDKB_I2C_ADDR 0x5F  
    #define TEXT_WIDTH 8  
    #define TEXT_HEIGHT 16      // Height of text to be printed and scrolled  
    #define BOTTOM_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)  
    #define TOP_FIXED_AREA 16   // Number of lines in top fixed area (lines counted from top of screen)  
    #define YMAX 320            // Bottom of screen area  
    // Arduino Uno R3/R4  
    #define TFT_DC 9  
    #define TFT_CS 10  
    Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);  
    // The initial y coordinate of the top of the scrolling area  
    uint16_t yStart = TOP_FIXED_AREA;  
    // yArea must be a integral multiple of TEXT_HEIGHT  
    uint16_t yArea = YMAX - TOP_FIXED_AREA - BOTTOM_FIXED_AREA;  
    // The initial y coordinate of the top of the bottom text line  
    uint16_t yDraw = YMAX - BOTTOM_FIXED_AREA - TEXT_HEIGHT;  
    // Keep track of the drawing x coordinate  
    uint16_t xPos = 0;  
    boolean escapeSeq = false;  
    // We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds  
    // for a full width line, meanwhile the serial buffer may be filling... and overflowing  
    // We can speed up scrolling of short text lines by just blanking the character we drew  
    int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking  
    void setup()  
         tft.setRotation(0); // Must be 0 to work vertical scrolling correctly  
         tft.setTextColor(ILI9341_BLACK, ILI9341_YELLOW);  
         tft.fillRect(0, 0, 240, 16, ILI9341_YELLOW);  
         tft.print("  Nano ESP32 Linux");  
         tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);  
         tft.setScrollMargins(TOP_FIXED_AREA, BOTTOM_FIXED_AREA);  
         for (byte i = 0; i < 18; i++) {  
           blank[i] = 0;  
    void loop(void)  
         while (Serial1.available()) {  
           char c =;  
           // If it is a CR or we are near end of line then scroll one line  
           if (c == '\r'  || xPos > 231) {  
             xPos = 0;  
             yDraw = scroll_line(); // It can take 13ms to scroll and blank 16 pixel lines  
           // delete key  
           if (c == 8) {  
             xPos -= TEXT_WIDTH;  
             Serial.print("\nDelete: ");  
             //tft.drawChar(xPos, yDraw, 219, ILI9341_BLACK, ILI9341_BLACK , 1);  
             tft.fillRect(xPos, yDraw, TEXT_WIDTH, TEXT_HEIGHT, ILI9341_BLACK);  
           // start of ANSI Escape Sequence  
           if (c == 27) {  
             escapeSeq = true;  
           if (c > 31 && c < 128) {  
             if (escapeSeq) {  
               if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {  
                 escapeSeq = false;  
             tft.drawChar(xPos, yDraw, c, ILI9341_WHITE, ILI9341_BLACK , 1);  
             xPos += TEXT_WIDTH;  
             blank[(18 + (yStart - TOP_FIXED_AREA) / TEXT_HEIGHT) % 19] = xPos; // Keep a record of line lengths  
         while (Serial.available()) {  
           char c =;  
         Wire1.requestFrom(CARDKB_I2C_ADDR, 1);  
         while (Wire1.available()) {  
           byte b =;  
           switch (b) {  
             case 0xA8: // Fn+C  
               Serial1.write(0x03); // Send Ctrl-C  
             case 0x96: // Fn+P  
               Serial1.write(0x10); // Send Ctrl-P  
             case 0x90: // Fn+R  
               Serial1.write(0x12); // Send Ctrl-R  
           char c = b;  
           if (c != 0) {  
             Serial.print(c, HEX);  
    int scroll_line() {  
         int yTemp = yStart; // Store the old yStart, this is where we draw the next line  
         // Use the record of line lengths to optimise the rectangle size we need to erase the top line  
         tft.fillRect(0, yStart, blank[(yStart - TOP_FIXED_AREA) / TEXT_HEIGHT], TEXT_HEIGHT, ILI9341_BLACK);  
         // Change the top of the scroll area  
         yStart += TEXT_HEIGHT;  
         // The value must wrap around as the screen memory is a circular buffer  
         if (yStart >= YMAX - BOTTOM_FIXED_AREA) {  
           yStart = TOP_FIXED_AREA + (yStart - YMAX + BOTTOM_FIXED_AREA);  
         // Now we can scroll the display  
         return  yTemp;  

    We need to install the Adafruit_ILI9341 library through the Arduino IDE Library Manager. Then, we can upload the sketch to the Uno R4 WiFi board.

View all 6 instructions

Enjoy this project?



Ale o co chodzi wrote 10/15/2023 at 17:51 point

can You use for minimize size of device, and add more power? meybe solar power too?

  Are you sure? yes | no

Ale o co chodzi wrote 09/09/2023 at 16:40 point

please add irda, cc1101 for 433MHz and 2 USB port (one A one C)

and mechanical swith to turn on-off this interface for reduce power

(and meybe decrease speed of memory/cpu etc.)

  Are you sure? yes | no

Gravis wrote 08/21/2023 at 13:20 point

I don't know if this info will help but there is this:

  Are you sure? yes | no

aaaaaa wrote 08/15/2023 at 10:37 point

meybe using fuzix?

Linux is good but how many weeks it can working on one charge battery?

  Are you sure? yes | no

Naveen wrote 08/15/2023 at 11:00 point

I did not check the power consumption. That will be next task. 


  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates