Replies: 1 comment
-
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Pinetime saves info like alarm time and settings to NRF's FDS (flash data storage) library now, which is Key-Value file system. FDS is also called as NVS (Non Volatile Storage). It's size is limited.
#2389
Pebble, Winamp, Rockbox, foobar, Roblox, Minecraft, Doom... A rich ecosystem of third-party plugins, like watchfaces and add-ons, encourages active participation from end-users, boosting the overall popularity of the software project. This makes it a must-have feature.
Pebble OS handles slow tasks like package copying on the watch itself, while offloading complex computations to the phone via a companion app. In essence, it uses the smartphone as a sort of co-processor.
Given PineTime's limited storage, we could store apps on the phone via BLEfs and dynamically load them over Bluetooth only when needed. This essentially allows us to run them on demand.
ChatGPT says:
FreeRTOS does not natively support dynamically loading and executing programs from a filesystem like Linux or Windows.
This is because FreeRTOS is a real-time operating system (RTOS) rather than a full-featured operating system. It provides task scheduling and synchronization primitives, but it does not include features such as:
However, there are several approaches depending on what you want to achieve.
1. Plugin-style modules (Recommended)
The most common approach is to load a binary containing functions rather than an entire application.
The application:
Example:
The plugin usually needs to be compiled as position-independent code (PIC) or designed to avoid absolute addresses.
2. Copy code into RAM and execute
If the MCU allows execution from SRAM (many ARM Cortex-M devices do), the process is:
Example:
Requirements:
3. Bootloader-based firmware update
This is the most common solution in embedded systems.
This is how most OTA (Over-The-Air) firmware updates work.
4. Implement an ELF loader
It is possible but significantly more complex.
A complete loader typically needs to implement:
Essentially, you would be implementing part of what Linux already provides.
Some open-source projects provide lightweight ELF loaders for embedded systems.
5. Use an interpreter (Lua, Python, WebAssembly)
Many embedded systems use scripting instead of native dynamic loading.
Example:
or
This allows new functionality to be added without replacing the firmware.
6. Position-Independent Code (PIC)
GCC options:
or
However, support for PIC on bare-metal ARM Cortex-M targets is often limited, and the generated code may not behave like PIC on desktop operating systems.
7. RTOSes with dynamic module support
Some embedded RTOSes include built-in support for loading executable modules.
dlmodulemechanism for dynamically loaded modules.These RTOSes provide more operating-system functionality than FreeRTOS, making dynamic loading much easier.
Which approach should you choose?
firmware.binIn practice, bootloader-based firmware updates and plugin-style modules are by far the most common approaches in FreeRTOS-based embedded systems. Full executable loading is possible but requires substantial additional infrastructure beyond what FreeRTOS itself provides.
Gemini says:
In FreeRTOS, dynamically loading and executing executable files from a file system is not natively supported out-of-the-box in the same way it is in full-fledged operating systems like Linux (which uses ELF loaders and the
execvesystem call). Because FreeRTOS is a real-time operating system (RTOS) designed for deeply embedded systems, it typically runs as a single, monolithic binary where all tasks and functions are linked statically at compile time.However, you can achieve dynamic loading in FreeRTOS. Here is how it is typically done, the formats used, and the challenges involved.
1. How It Works (The Core Mechanism)
To load and run an executable dynamically from a file system (such as an SD card using FATFS) in FreeRTOS, you need three main components:
2. Common Approaches and Formats
A. ELF (Executable and Linkable Format) Loader
The standard way to do this is by using relocatable ELF files (usually compiled with the
-ror-sharedflag in GCC).pvPortMallocor dedicated fast RAM) for the.text(code),.rodata(read-only data), and.data/.bss(variables) sections.vTaskDelayorxQueueSend) by mapping the ELF's import table to the actual function addresses in your main FreeRTOS firmware.B. PIC (Position Independent Code) Binaries
Another approach is compiling your dynamic module as Position Independent Code using the
-fPICcompiler flag.C. WebAssembly (Wasm) or MicroPython Engines
Instead of loading native machine code, many modern FreeRTOS systems load bytecode.
.wasmfiles on your file system, load them into memory, and run them securely in a virtual machine environment on FreeRTOS.3. Open-Source Libraries for FreeRTOS ELF Loading
If you want to implement native dynamic loading, you don't have to write an ELF loader from scratch. You can use existing lightweight loaders:
4. Key Challenges & Considerations
Before implementing dynamic loading in FreeRTOS, keep these critical hardware constraints in mind:
printforvTaskDelayto the dynamic module.DeepSeek says:
Dynamic Loading of Executable Files from a File System in FreeRTOS
1. Fundamental Understanding: FreeRTOS as a Static Environment
It's important to first understand that FreeRTOS is fundamentally a real-time kernel (a scheduler with synchronization primitives) that is typically statically linked with your application into a single monolithic binary . Unlike general-purpose operating systems (GPOS) such as Linux or Windows, it does not natively support the concept of dynamically loading and executing arbitrary user programs as separate processes . A FreeRTOS "task" is more analogous to a thread than a GPOS process—it shares the same memory space and does not inherently have memory protection from other tasks .
However, implementing dynamic loading is possible, but it requires significant custom development. This is often done for advanced use cases like plugin systems, firmware updates, or running large libraries that cannot fit in internal flash memory .
2. The Required Architecture and Key Components
To achieve dynamic loading, you need to build an architecture with several key components.
2.1. File System Integration
First, you need a file system that can read the executable file from storage (e.g., an SD card, external QSPI flash, or a RAM disk) .
.bin,.axf, or.elffile) will be stored on this medium .2.2. Dynamic Memory Manager
The executable's code and data segments need to be loaded into RAM for execution. You will need a heap memory manager to allocate memory for these segments at runtime . Many FreeRTOS ports include a heap manager (
heap_1.ctoheap_5.c), but you may need a more sophisticated one that can handle arbitrary allocation and deallocation of blocks of memory .2.3. Executable File Format and Loader
You must choose a file format and implement a loader to parse and load it into memory.
.text(code) and.data(initialized data) segments.2.4. Dynamic Linking (Relocation)
This is the most complex part. Your loader must resolve symbols (function and variable references) that the loaded program needs. This requires :
xQueueSend, driver functions likeST7735_Message).3. Execution and Integration with FreeRTOS
Once the code is loaded and linked, it's not automatically a task. You can follow a few strategies to integrate it:
module_main()). After loading, your firmware calls this function directly or creates a single task with it as the entry point .plugin_init,plugin_process). The host can retrieve these function pointers by name.4. Additional Considerations and Constraints
ChatGPT Answer:
Very few lightweight RTOSes provide official support for dynamically loading executable files (such as ELF modules). Most lightweight RTOSes use static linking, where all code is linked into a single firmware image at build time.
dlopen()dlmoduleApache NuttX
NuttX is the closest to a traditional Unix-like operating system.
It supports:
dlopen()dlsym()It is the most mature option if you need to execute ELF files directly from a filesystem.
Zephyr
Zephyr provides Loadable Extensions (LLEXT).
Features include:
LLEXT is intended for extending an application rather than running independent user programs.
RT-Thread
RT-Thread includes dlmodule, which supports:
It is simpler than NuttX but suitable for many embedded applications.
Other RTOSes
Most lightweight RTOSes do not support dynamic loading, including:
These systems typically follow this workflow:
Lightweight ranking (among RTOSes that support dynamic loading)
For resource-constrained hardware such as the PineTime (nRF52832, Cortex-M4F, 64 KB RAM):
Gemini:
While many microcontrollers natively run as a single, statically-linked binary, a few lightweight, open-source RTOSes provide native, structured subsystems designed explicitly to parse, load, relocate, and run compiled executable files (usually ELF files) directly from a file system.
The most prominent lightweight RTOSes that natively support dynamic loading of modules include:
1. Zephyr RTOS (LLEXT Subsystem)
Zephyr includes a highly polished framework specifically for this purpose called LLEXT (Linkable Loadable Extensions).
llext_fs_loader) or from a memory buffer (llext_buf_loader)..init_array) inside the binary.2. RT-Thread (dlmodule)
RT-Thread (a very popular open-source RTOS in IoT devices) features a dedicated kernel-space component called dlmodule (formerly known as the Application Module).
How it handles files: It compiles modules independently of the main kernel into custom executable extensions:
.mofiles: Executable dynamic modules. When loaded, the RT-Thread kernel automatically provisions a main thread to execute the module's code and can even pass command-line arguments (argc,argv)..sofiles: Shared libraries that can reside in RAM to be called by other modules.Features: It integrates seamlessly with RT-Thread’s virtual file system (DFS) and POSIX layer, enabling standard
dlopen(),dlsym(), anddlclose()functionality on resource-constrained microcontrollers.3. NuttX (BINFMT & ELF/NXFLAT)
Apache NuttX is a deeply POSIX-compliant RTOS designed to mimic Linux but run on microcontrollers. Because of its POSIX nature, dynamic loading is one of its core architectural features.
4. Contiki-NG (ELF Loader)
If your hardware is incredibly constrained (e.g., old 8-bit or 16-bit MCUs, or ultra-low-power wireless sensor nodes), Contiki-NG is a lightweight OS designed for the "Internet of Things."
Comparison Summary
.elf).mo,.so)dlopenfunctionality, boots an automatic main thread.co)DeepSeek:
Several lightweight RTOSes support dynamic loading of executable modules or files. Here are the most notable options:
RT-Thread
RT-Thread provides a robust Dynamic Module (
dlmodule) feature that supports loading two types of files:.mofiles: Executable modules that can be loaded and run, automatically creating a main thread that executes themain()function..sofiles: Dynamic libraries that can be loaded into memory and used by other programs or modules.The kernel exports functions to dynamic modules using the
RTM_EXPORT()macro, and you can list all exported symbols with thelist_symbolscommand. Dynamic modules are compiled with Position-Independent Code (PIC) flags (-fPIC) to support runtime loading.Apache NuttX
NuttX offers two approaches for dynamic loading:
NXFLAT Binary Format: A customized and simplified binary format designed for deeply embedded environments without MMU. Key features include:
.datasection to RAM when using ROMFSELF Loading: NuttX also supports loading standard ELF binaries dynamically, making it very Unix/Linux-like for microcontrollers.
Zephyr RTOS
Zephyr introduced Linkable Loadable Extensions (LLEXT) starting from v3.5.0. This feature allows you to:
The LLEXT feature is particularly useful for AI/ML applications where models and runtimes need frequent updates during development. Currently, LLEXT primarily supports ARMv7 architecture.
Azure RTOS ThreadX
ThreadX provides a Module feature that enables dynamic loading and unloading of application modules at runtime. Notable characteristics:
PX5 RTOS
PX5 offers a MODULES technology that natively supports dynamic loading of separately built application modules. Key advantages:
Other Options
Part Only RTOS: A research project designed for 8-bit ATmega2560 microcontrollers that can dynamically load
.binmodules from an SD card, with a kernel occupying less than 2.5KB of Flash.eRTOS: Supports Real-Time Dynamic Link Libraries (RTDLLs) that can be loaded either implicitly (through export libraries) or explicitly (using
LoadLibrarycalls).When choosing an RTOS, consider factors like memory footprint, architecture support (ARM, RISC-V, Xtensa, etc.), MMU/MPU availability for memory protection, and the complexity of your dynamic loading requirements.
ChatGPT:
How does PebbleOS implement package installation and removal?
PebbleOS supports installing and removing application packages by managing each application as an independent package, separate from the operating system itself. Unlike a typical MCU firmware, where all functionality is linked into a single binary, PebbleOS includes an Application Manager responsible for package management.
The architecture is roughly as follows:
1. Application Manager
PebbleOS contains components such as an Application Manager, Application Installation Manager, and Process Manager.
Their responsibilities include:
2. PBW Package Format
Applications are distributed as
.pbwpackages.When installed, the package is stored in flash as an independent application:
Each application contains its own executable and resources.
3. Independent Application Loading
Applications are separate from the operating system.
When launching an application, PebbleOS sets up:
before transferring execution to the application.
This allows applications to be installed or replaced without reflashing the operating system.
4. Flash Storage Management
PebbleOS manages flash storage as a collection of application packages.
Initially:
After removing an application:
When a new application is installed:
The Application Manager reuses or reorganizes available flash space as needed.
5. The Phone Acts as the Package Manager
One interesting aspect of PebbleOS is that much of the package management logic resides on the paired smartphone.
The watch itself mainly performs:
If storage becomes full, the phone decides which applications remain installed and can remove existing packages before installing new ones.
Comparison with FreeRTOS
A typical FreeRTOS-based system follows this model:
PebbleOS instead uses:
This architecture keeps the operating system fixed while allowing applications and watchfaces to be independently installed, removed, updated, and launched without reflashing the entire firmware.
Gemini:
PebbleOS (the FreeRTOS-based operating system that powered Pebble smartwatches) implemented a unique, resource-constrained model for package installation and removal. Because the hardware had highly limited RAM (often under 128KB) and a relatively small amount of external Flash storage, it relied heavily on a companion smartphone app to act as its heavy-lifter, installer, and storage locker.
Here is a breakdown of how PebbleOS handled the installation, execution, and removal of packages (applications and watchfaces).
1. The Package Format:
.pbw(Pebble Bundle Wrapper)Before an app can be installed, it exists as a
.pbwfile. A.pbwfile is essentially a renamed ZIP archive that contains:appinfo.json: Metadata including the app's UUID, name, company, version, and required capabilities.pebble-app.bin: The compiled ARM Cortex-M machine code (binary) for the watch app.pebble-js-app.js(Optional): JavaScript code meant to run on the phone (via PebbleKit JS) to handle internet requests, GPS, or heavy computations.resources.pbpack: A binary bundle of localized strings, images, and fonts compiled specifically for the watch's display architecture.2. The Installation Process
PebbleOS itself did not have the storage or processing power to parse complex archives, manage a large marketplace, or store dozens of apps simultaneously. Instead, the installation pipeline was split between the phone and the watch.
Step A: The Phone App Handler
.pbwfile (from the app store or via sideloading), the Pebble Mobile App interceptively handles the file.appinfo.json, and registers the app's unique UUID into the phone's local database ("App Locker").pebble-js-app.js), the phone isolates this code to run within the mobile app's background environment.Step B: Transmission via Pebble Protocol (PPo)
pebble-app.binandresources.pbpackover Bluetooth.Step C: Watch-Side Allocation and Storage
3. Dynamic Loading & Execution (The "App Locker" System)
Early versions of PebbleOS could only hold 8 apps at a time. Later versions introduced a dynamic paging system that treated the watch's flash storage as a cache and the smartphone's App Locker as the primary hard drive.
.text(code) and.datasections into RAM. Because the ARM Cortex-M architecture allows it, some variations allowed executing code directly from flash via XIP (Execute-In-Place) to conserve RAM, though resource assets were kept separate.4. The Removal Process
Because apps are self-contained within specific, isolated flash slots and managed via a central UUID lookup registry, removal is incredibly lightweight and fast.
Triggered by the Phone or Cache eviction
When a user deletes an app from their phone, or if the watch runs out of flash slots and needs to overwrite an old app to make room for a new one:
.pbwis streamed to the watch, the storage manager will cleanly overwrite those blocks.How does Rockbox OS implement its internal filesystem, dynamic executable loading, and dynamic user data storage?
ChatGPT Answer
Rockbox differs from a typical RTOS. It is a single firmware image that provides a plugin system and makes extensive use of the device's filesystem.
The three features can be summarized as follows:
.rockfiles)1. Internal Filesystem
Rockbox does not implement its own filesystem.
Instead, it uses the storage device's existing filesystem, typically:
A typical directory layout looks like this:
The
.rockboxdirectory contains system resources such as:2. Dynamic Executable Loading
Yes, Rockbox supports dynamic loading of executable modules.
However, unlike Linux, it does not load ELF executables.
Instead, it loads Rockbox-specific plugin (
.rock) files.The execution flow is:
Every plugin exports an entry point:
The operating system exposes its services through a plugin API table, allowing plugins to access filesystem, display, audio, input, and other services without directly linking against the firmware.
For example:
This architecture is conceptually similar to a simplified
dlopen()mechanism.3. Plugin Architecture
The overall structure is:
Rather than calling internal firmware functions directly, plugins communicate through the exported API table.
This provides ABI compatibility while allowing plugins to be loaded independently.
4. Dynamic User Data Storage
Rockbox fully supports dynamic file creation and modification.
Examples include:
Plugins are also free to create their own files, for example:
These files are stored directly in the filesystem.
5. Dynamic Resources
Rockbox also treats resources as regular files.
Examples include:
New fonts, themes, icons, and language packs can be added or removed simply by copying or deleting files—no firmware recompilation is required.
Overall Architecture
Summary
Although Rockbox is not an RTOS, it provides several advanced features that are uncommon in embedded firmware:
.rockplugin modulesUnlike PebbleOS, Rockbox does not use a package management system. Instead, it relies on a combination of filesystem-based resources and a plugin loader to provide dynamic extensibility.
Beta Was this translation helpful? Give feedback.
All reactions