DEV Community

Cyber Code Master
Cyber Code Master

Posted on

Modular External-Firmware Architecture for Arduino UNO R4 WiFi

1. Executive Summary

This report describes a proposed architecture for overcoming the practical program-size limitation of a microcontroller by dividing a large application into independently loadable firmware modules stored in external non-volatile storage.

The core concept is:

Only the currently required module must occupy the Arduino's internal program Flash, while the complete collection of modules can reside in much larger external storage.

For the Arduino UNO R4 WiFi, the main Renesas RA4M1 MCU has a 48 MHz Cortex-M4 CPU, 256 KB code Flash, 32 KB SRAM, and 8 KB data Flash. The board also contains an ESP32-S3-MINI-1-N8 dedicated to Wi-Fi/Bluetooth connectivity.

The proposed architecture adds an external storage device, called X, containing firmware modules, application assets, update packages, backups, and metadata.

The system can then operate approximately as follows:

                 External Storage X
        ┌──────────────────────────────┐
        │ Module 001                   │
        │ Module 002                   │
        │ Module 003                   │
        │ Module 004                   │
        │ ...                          │
        │ OTA packages                 │
        │ Backup versions              │
        │ Configuration/state          │
        └──────────────┬───────────────┘
                       │
                       │ SPI
                       ▼
              ┌─────────────────┐
              │     RA4M1        │
              │                  │
              │ Permanent loader │
              │ + active module  │
              └─────────────────┘
Enter fullscreen mode Exit fullscreen mode

This can make the total project storage dramatically larger than the MCU's internal Flash, but it does not make the MCU magically capable of executing an arbitrarily large program simultaneously. Only code that fits in the active execution environment can execute at once.

The architecture is therefore most useful for:

  • large sequential applications
  • automation systems
  • robots
  • instrumentation
  • data-processing devices
  • menu-driven embedded applications
  • devices with infrequently used functionality
  • modular firmware
  • OTA-delivered functionality
  • cartridge-like application systems

It is much less suitable for applications requiring all components to remain resident and available with extremely low latency, such as a high-throughput server-like workload.


2. The Original Problem

A conventional microcontroller application has a structure similar to:

Application
     │
     ▼
Compiler
     │
     ▼
One firmware image
     │
     ▼
Internal MCU Flash
Enter fullscreen mode Exit fullscreen mode

The maximum executable program is therefore constrained by the MCU's available code Flash.

For the UNO R4 WiFi, the RA4M1 provides:

  • 256 KB code Flash
  • 32 KB SRAM
  • 8 KB data Flash
  • 48 MHz Cortex-M4 CPU

The source-code line count itself is not the true limit. A 5,000-line application can be larger than another 20,000-line application depending on libraries, tables, constants, generated code, and compiler output.

The meaningful quantity is the compiled executable size.


3. The Proposed Solution

The proposed solution introduces an external storage system called X.

Instead of compiling a huge application into one enormous firmware image:

Huge application
        ↓
One firmware
        ↓
Too large
Enter fullscreen mode Exit fullscreen mode

the application is divided:

Huge application
        ↓
┌────────┬────────┬────────┬────────┐
│Module 1│Module 2│Module 3│Module 4│ ...
└────────┴────────┴────────┴────────┘
        ↓
External storage X
Enter fullscreen mode Exit fullscreen mode

The MCU only loads the currently needed module into its executable Flash area.

Conceptually:

Module 1
   ↓
execute
   ↓
finish / switch
   ↓
load Module 2
   ↓
execute
   ↓
load Module 3
   ↓
execute
Enter fullscreen mode Exit fullscreen mode

This resembles concepts historically known as overlays, paged code, or loadable modules, although the implementation here is specifically designed for an embedded microcontroller.


4. UNO R4 WiFi Hardware Foundation

The UNO R4 WiFi has two processors.

4.1 RA4M1

The RA4M1 is the primary MCU connected to the Arduino headers.

It provides:

48 MHz Cortex-M4
256 KB code Flash
32 KB SRAM
8 KB data Flash
Enter fullscreen mode Exit fullscreen mode

and the usual GPIO/peripheral functionality.

4.2 ESP32-S3

The UNO R4 WiFi also contains an ESP32-S3 module for Wi-Fi and Bluetooth connectivity. Arduino documents it as the secondary MCU, communicating with the RA4M1 through a logic-level translator.

This creates an especially interesting platform:

        UNO R4 WiFi
              │
      ┌───────┴────────┐
      │                │
      ▼                ▼
   RA4M1            ESP32-S3
   execution        networking
   hardware         Wi-Fi/BLE
Enter fullscreen mode Exit fullscreen mode

The ESP32-S3 can therefore be used as the networking/update component while the RA4M1 remains responsible for the primary embedded application.


5. Important Hardware Correction: X Interface

An earlier version of this idea proposed QSPI Flash directly attached to the RA4M1.

For the actual UNO R4 WiFi, this needs correction.

The RA4M1 variant used by the UNO R4 WiFi provides SPI, but Renesas lists zero QSPI and zero OSPI interfaces and no external memory bus for the relevant device.

Therefore, on this exact board, a practical X implementation would use:

Option A — SPI NOR Flash

RA4M1
  │
  │ SPI
  ▼
SPI NOR Flash
Enter fullscreen mode Exit fullscreen mode

Advantages:

  • simple
  • compact
  • non-volatile
  • predictable
  • suitable for firmware storage
  • electrically straightforward

Option B — microSD

RA4M1
  │
  │ SPI
  ▼
microSD
Enter fullscreen mode Exit fullscreen mode

Advantages:

  • enormous capacity
  • removable
  • very convenient for experimentation

Disadvantages:

  • latency can be less predictable
  • filesystem overhead
  • card behavior varies
  • less deterministic than dedicated NOR Flash

Option C — ESP32-S3 as storage/network intermediary

The ESP32-S3 can act as a second computing/storage subsystem.

This is particularly interesting for OTA:

Internet
   │
Wi-Fi
   │
ESP32-S3
   │
communication
   │
RA4M1
Enter fullscreen mode Exit fullscreen mode

Best conceptual distinction

For a fast deterministic embedded system:

SPI NOR Flash → X

For maximum capacity and easy experimentation:

microSD → X

For OTA/network functionality:

ESP32-S3 → network/update subsystem


6. Proposed System Architecture

A robust implementation should not treat every module as an entirely independent Arduino sketch.

Instead, create a permanent resident layer.

┌────────────────────────────────────────┐
│             RA4M1 INTERNAL FLASH       │
│                                        │
│  Boot / recovery code                  │
│  Module loader                         │
│  Hardware abstraction                  │
│  State manager                         │
│  Communication layer                   │
│  Error/recovery system                 │
│  Active application module             │
└───────────────────────┬────────────────┘
                        │
                        │ SPI
                        ▼
┌────────────────────────────────────────┐
│                 X                      │
│                                        │
│ Module 001                             │
│ Module 002                             │
│ Module 003                             │
│ Module 004                             │
│ ...                                    │
│ Application data                       │
│ OTA package                            │
│ Backup firmware                        │
│ Metadata                               │
└────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The permanent resident layer is important because otherwise every module would have to duplicate:

  • startup code
  • drivers
  • communication routines
  • storage handling
  • error handling
  • module-management code

That would waste both Flash and development effort.


7. Module Concept

Each module should be a compiled binary, not source code.

For example:

module_001.bin
module_002.bin
module_003.bin
module_004.bin
Enter fullscreen mode Exit fullscreen mode

The module can have a small header:

┌─────────────────────────────┐
│ Magic                       │
│ Module ID                   │
│ Version                     │
│ Target MCU                  │
│ Required runtime version    │
│ Start address               │
│ Image size                  │
│ CRC/hash                    │
│ Digital signature           │
│ Dependencies                │
│ Entry point                 │
└─────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

This lets the loader determine:

  • whether the module is valid
  • what version it is
  • whether it is compatible
  • whether its binary is corrupted
  • where to place it
  • what dependencies it expects

8. Example 99,999-Line Project

Suppose a hypothetical project has approximately:

99,999 source lines
Enter fullscreen mode Exit fullscreen mode

Instead of creating one huge firmware image:

99,999 lines
      ↓
one giant executable
      ↓
doesn't fit
Enter fullscreen mode Exit fullscreen mode

divide it:

Project
│
├── Module 01
├── Module 02
├── Module 03
├── Module 04
├── ...
└── Module 100
Enter fullscreen mode Exit fullscreen mode

Suppose every compiled module is ≤ 180 KB.

Then:

Module 01 → fits
Module 02 → fits
Module 03 → fits
...
Module 100 → fits
Enter fullscreen mode Exit fullscreen mode

X could hold all 100 modules.

The theoretical total program repository might therefore be:

180 KB × 100
≈ 18 MB
Enter fullscreen mode Exit fullscreen mode

while the RA4M1 executes only one module at a time.

This is the fundamental scaling mechanism.


9. The Crucial Limitation

The system does not turn the 256 KB MCU into an 18 MB MCU.

Instead:

Internal execution capacity
        ↓
~one active module

External repository capacity
        ↓
many modules
Enter fullscreen mode Exit fullscreen mode

Therefore:

Total available application storage becomes large, but simultaneous executable state remains limited.

This distinction is fundamental.


10. Module Independence

Your original idea specifically assumes that each part can run independently.

That is the easiest case.

For example:

Module 1:
Turn LED on
Read sensor
Move actuator
Finish

Module 2:
Display information
Read button
Finish

Module 3:
Run calibration
Store result
Finish
Enter fullscreen mode Exit fullscreen mode

These are good candidates.

Problems occur when:

Module 1 creates variable A
Module 2 constantly needs variable A
Module 3 depends on timers from Module 1
Module 4 expects an interrupt handler from Module 2
Enter fullscreen mode Exit fullscreen mode

Once one module disappears, its RAM, functions, interrupt handlers, and execution context disappear with it.

Therefore a shared persistent state system is needed.


11. Persistent State Architecture

A separate state layer can store important information.

             Module 1
                 │
                 ▼
          State Manager
                 │
       ┌─────────┼─────────┐
       ▼         ▼         ▼
    EEPROM     FRAM     external X
Enter fullscreen mode Exit fullscreen mode

For example:

state:
  current_module = 4
  sensor_value = 821
  job_id = 1284
  calibration = valid
  progress = 73%
Enter fullscreen mode Exit fullscreen mode

Then Module 5 can reconstruct the required context.

This converts:

Module → Module
Enter fullscreen mode Exit fullscreen mode

into:

Module
  ↓
shared persistent state
  ↓
next module
Enter fullscreen mode Exit fullscreen mode

12. Reboot-Based Switching

The simplest implementation is:

Module 1
   ↓
request next module
   ↓
save state
   ↓
reset
   ↓
loader starts
   ↓
load Module 2
   ↓
reset/start
   ↓
Module 2
Enter fullscreen mode Exit fullscreen mode

This is relatively easy to reason about.

Advantages:

  • clean execution boundary
  • simple memory management
  • simple recovery
  • module has a known startup state
  • fewer runtime relocation problems

Disadvantages:

  • switching latency
  • peripheral reinitialization
  • loss of live RAM context
  • network connections may be interrupted
  • timers may need restoration

13. Non-Reboot Module Switching

A more advanced architecture could switch modules without resetting the entire MCU.

Conceptually:

Module A running
       ↓
loader
       ↓
replace active module
       ↓
Module B running
Enter fullscreen mode Exit fullscreen mode

This resembles dynamic code overlays.

However, this is considerably more difficult because the system needs to manage:

  • code locations
  • RAM
  • function pointers
  • stack state
  • interrupts
  • peripheral state
  • dependencies
  • shared libraries
  • module ABI compatibility

Therefore:

Version 1

Use reboot-based switching.

Version 2

Consider live module switching.


14. Loading-Time Analysis

This is one of the most important engineering questions.

The transfer time from X is not the entire module-switching time.

A simplified equation is:

T_total =
    T_detect
  + T_read
  + T_erase
  + T_program
  + T_verify
  + T_reset
  + T_startup
Enter fullscreen mode Exit fullscreen mode

For example:

200 KB module
Enter fullscreen mode Exit fullscreen mode

External SPI transfer

The RA4M1 SPI electrical characteristics list an upper RSPCK value of 16 MHz for the relevant interface conditions.

At 16 Mbit/s, the theoretical raw transfer time of 200 KiB is approximately:

204,800 × 8 / 16,000,000
≈ 102 ms
Enter fullscreen mode Exit fullscreen mode

That is only the wire transfer.

Real time will be greater due to:

  • commands
  • addressing
  • chip-select transitions
  • software overhead
  • buffering
  • protocol headers
  • verification

15. Internal Flash Programming Is the Bigger Issue

This is extremely important.

The RA4M1's Flash itself has non-trivial programming and erase times.

Renesas specifies, under high-speed operation:

  • 8-byte programming: typical 54 µs, maximum 506 µs at FCLK = 32 MHz
  • 2 KB erase: typical 5.67 ms, maximum 222 ms

Therefore simply reading a 200 KB module from X is not the whole cost.

A rough component-level calculation for 200 KiB gives:

200 KiB / 8 bytes
≈ 25,600 programming operations
Enter fullscreen mode Exit fullscreen mode

Using the typical 54 µs figure:

25,600 × 54 µs
≈ 1.38 seconds
Enter fullscreen mode Exit fullscreen mode

For erasing 2 KB blocks:

200 KiB / 2 KiB
≈ 100 blocks
Enter fullscreen mode Exit fullscreen mode

Typical erase time:

100 × 5.67 ms
≈ 0.57 seconds
Enter fullscreen mode Exit fullscreen mode

Therefore the basic Flash-operation components alone can approach ~1.95 seconds, before software overhead, transfer, verification, and reboot are included.

These are calculations from Renesas' per-operation specifications, not a guaranteed real-world module-switching benchmark. Actual implementation needs measurement.

This corrects our earlier rough assumption that a 200 KB module might always switch in only tens of milliseconds.


16. Practical Transition-Time Expectations

For a reboot-and-reflash architecture:

External read
       +
Flash erase
       +
Flash programming
       +
verification
       +
startup
Enter fullscreen mode Exit fullscreen mode

A realistic target should therefore initially be considered hundreds of milliseconds to several seconds, depending on module size and implementation.

For a 200 KB module, around 2 seconds of Flash-operation time is plausible from the datasheet-derived calculation, with actual measured time potentially different.

This means the system is viable for applications where a module change every few seconds, minutes, or longer is acceptable.

It is not appropriate for:

10,000 module swaps/second
Enter fullscreen mode Exit fullscreen mode

or anything remotely similar.


17. Flash Wear

There is another major issue: internal Flash endurance.

Renesas specifies a minimum 1,000 reprogram/erase cycles per code-Flash block under the stated conditions.

Therefore repeatedly replacing the same active region can eventually wear it.

For example:

Load Module A
erase
write

Load Module B
erase
write

Load Module C
erase
write
...
Enter fullscreen mode Exit fullscreen mode

is not something to perform indefinitely without a wear strategy.

Potential solutions:

A/B active slots

Slot A
Slot B

A → B → A → B → ...
Enter fullscreen mode Exit fullscreen mode

This spreads wear across physical blocks.

Multiple slots

Slot 1
Slot 2
Slot 3
Slot 4
...
Enter fullscreen mode Exit fullscreen mode

Keep frequently changing data outside code Flash

Use:

  • external Flash
  • FRAM
  • data Flash
  • other persistent storage

for changing state.

The core rule is:

Do not use the RA4M1 code Flash as if it were unlimited scratch storage.


18. OTA Update Extension

The architecture becomes significantly more powerful when combined with the UNO R4 WiFi's ESP32-S3.

Arduino already documents the UNO R4 WiFi as capable of using Arduino Cloud and uploading code over the air.

Your custom architecture could extend the same general concept to the module system.

Instead of:

PC
 ↓
USB
 ↓
Arduino
Enter fullscreen mode Exit fullscreen mode

you could have:

Internet
   ↓
Wi-Fi
   ↓
ESP32-S3
   ↓
download module
   ↓
X
   ↓
RA4M1 loader
Enter fullscreen mode Exit fullscreen mode

19. OTA Module Update Process

A robust OTA sequence could be:

1. Device runs Module 4

2. ESP32-S3 checks update server

3. Server reports:
   Module 5 v2.3 available

4. ESP32-S3 downloads package

5. Package is stored in X

6. Hash/checksum is verified

7. Digital signature is verified

8. Package metadata is validated

9. New version marked "pending"

10. RA4M1 switches to new module

11. New module boots

12. Health test runs

13. Module reports success

14. Version becomes "active"
Enter fullscreen mode Exit fullscreen mode

This gives you a proper update state machine.


20. A/B OTA Strategy

A robust design should never immediately destroy the currently working version.

Instead:

X
├── Active
│   └── v1.4
│
├── Candidate
│   └── v1.5
│
└── Backup
    └── v1.3
Enter fullscreen mode Exit fullscreen mode

Update:

v1.4 running
     ↓
download v1.5
     ↓
verify
     ↓
boot v1.5
     ↓
self-test
     ↓
success
     ↓
v1.5 becomes active
Enter fullscreen mode Exit fullscreen mode

If it fails:

v1.5 fails
   ↓
watchdog/reset
   ↓
recovery loader
   ↓
restore v1.4
Enter fullscreen mode Exit fullscreen mode

This is far safer than simply overwriting the only known-good image.


21. OTA Security

For a real product, checksum alone is not enough.

A checksum answers:

"Did the data become corrupted?"

A cryptographic signature answers:

"Did this firmware originate from an authorized publisher?"

Therefore the package should ideally use:

Firmware
   ↓
Hash
   ↓
Digital signature
   ↓
Package
Enter fullscreen mode Exit fullscreen mode

The device verifies:

signature valid?
        │
   ┌────┴────┐
  YES        NO
   │          │
install      reject
Enter fullscreen mode Exit fullscreen mode

This prevents an attacker who can modify the download from simply replacing the module with arbitrary firmware.

The RA4M1 itself includes security-related hardware features such as a true random-number generator and AES/GHASH capabilities.


22. Server-Like Applications

This is where your own observation becomes important.

A server-like system usually needs many components simultaneously:

Network
Database
Authentication
Request handling
Timers
Background tasks
Logging
Connection state
Enter fullscreen mode Exit fullscreen mode

Those components cannot conveniently disappear and reappear every few seconds.

For example:

Client request
      ↓
Network layer
      ↓
Authentication
      ↓
Database
      ↓
Response
Enter fullscreen mode Exit fullscreen mode

If every transition requires:

save
reflash
reset
restore
Enter fullscreen mode Exit fullscreen mode

latency becomes unacceptable.

Therefore your architecture is not a universal replacement for sufficient RAM/Flash.


23. Hybrid Architecture for Difficult Projects

The strongest design is a hybrid system.

Keep latency-sensitive components permanently resident:

┌──────────────────────────────────────┐
│ RA4M1 Permanent Runtime              │
│                                      │
│ Scheduler                            │
│ Interrupt handlers                   │
│ Critical drivers                     │
│ Communication                       │
│ State manager                        │
│ Time-critical control                │
└──────────────────┬───────────────────┘
                   │
              Module system
                   │
                   ▼
          External storage X
Enter fullscreen mode Exit fullscreen mode

Then load only less-frequent functionality.

For example:

Permanent:
- motor control
- safety
- timer
- sensor sampling

Modules:
- calibration
- diagnostics
- display menus
- advanced algorithms
- optional features
Enter fullscreen mode Exit fullscreen mode

This is much more practical.


24. Recommended Division of Labor

Because the UNO R4 WiFi contains both RA4M1 and ESP32-S3, the system could be structured as:

                    UNO R4 WiFi
                         │
            ┌────────────┴────────────┐
            │                         │
            ▼                         ▼
        RA4M1                     ESP32-S3
     real-time MCU             connectivity MCU
            │                         │
            │                         ├── Wi-Fi
            │                         ├── OTA
            │                         ├── cloud
            │                         └── update server
            │
            ├── sensors
            ├── motors
            ├── GPIO
            └── module runtime
                    │
                    ▼
                   X
Enter fullscreen mode Exit fullscreen mode

This plays to the strengths of both MCUs.

Arduino confirms that the RA4M1 is the main MCU connected to the board's pins, while the ESP32-S3 is the secondary wireless MCU.


25. Recommended X Storage Layout

A useful X filesystem/layout could look like:

/X
│
├── /boot
│   └── recovery.bin
│
├── /modules
│   ├── 0001/
│   │   ├── manifest.bin
│   │   └── firmware.bin
│   │
│   ├── 0002/
│   │   ├── manifest.bin
│   │   └── firmware.bin
│   │
│   └── 0003/
│       ├── manifest.bin
│       └── firmware.bin
│
├── /ota
│   ├── candidate.bin
│   └── candidate.manifest
│
├── /backup
│   └── known-good.bin
│
└── /state
    └── system.dat
Enter fullscreen mode Exit fullscreen mode

26. Module Manager

The module manager would be the heart of the system.

Its responsibilities would include:

detect module
verify module
check compatibility
select destination
erase Flash
program Flash
verify Flash
restore state
set boot target
reset
recover on failure
Enter fullscreen mode Exit fullscreen mode

A simple state machine could be:

IDLE
  ↓
CHECK_MODULE
  ↓
VALIDATE
  ↓
PREPARE
  ↓
ERASE
  ↓
PROGRAM
  ↓
VERIFY
  ↓
COMMIT
  ↓
RESET
  ↓
BOOT_MODULE
Enter fullscreen mode Exit fullscreen mode

Failure at any stage:

        ERROR
          ↓
      RECOVERY
          ↓
   previous known-good
Enter fullscreen mode Exit fullscreen mode

27. Module ABI

One of the hardest long-term problems is compatibility.

Suppose Module 7 expects:

runtime API v2
Enter fullscreen mode Exit fullscreen mode

but your permanent loader provides:

runtime API v1
Enter fullscreen mode Exit fullscreen mode

The module may fail.

Therefore every module should identify:

Runtime ABI version
Enter fullscreen mode Exit fullscreen mode

For example:

Module:
  ID: 7
  Version: 4.2
  ABI: 3
Enter fullscreen mode Exit fullscreen mode

Loader:

Supported ABI: 1-3
Enter fullscreen mode Exit fullscreen mode

Then the loader can reject incompatible modules before programming them.


28. Source Code Organization

A giant project should be organized intentionally.

For example:

project/
│
├── core/
│   ├── hardware/
│   ├── state/
│   ├── communication/
│   └── loader/
│
├── modules/
│   ├── sensors/
│   ├── diagnostics/
│   ├── calibration/
│   ├── ui/
│   └── automation/
│
├── shared/
│   ├── structures/
│   ├── protocols/
│   └── constants/
│
└── build/
    ├── module001.bin
    ├── module002.bin
    └── ...
Enter fullscreen mode Exit fullscreen mode

This makes the architecture manageable rather than simply splitting arbitrary portions of one giant file.


29. What Happens to RAM?

This is a crucial distinction.

Your technique primarily solves:

FLASH / CODE SIZE
Enter fullscreen mode Exit fullscreen mode

It does not solve:

RAM
Enter fullscreen mode Exit fullscreen mode

If one module requires:

50 KB RAM
Enter fullscreen mode Exit fullscreen mode

the UNO R4 WiFi cannot magically execute it just because X contains enough storage.

The RA4M1 has only 32 KB SRAM.

Therefore every module must individually respect the RAM limit unless additional memory hardware or a different processor is used.

This means:

Large X
   ≠
Large RAM
Enter fullscreen mode Exit fullscreen mode

30. What About Data?

Application data can be separated from application code.

For example:

X
├── Firmware modules
├── Machine configuration
├── Images/assets
├── Calibration data
├── Logs
└── OTA packages
Enter fullscreen mode Exit fullscreen mode

This can make X significantly more useful than merely storing executable modules.


31. Cartridge Version

Your original physical-cartridge idea can also be implemented.

Conceptually:

             UNO R4 WiFi
                  │
             cartridge slot
                  │
             ┌────▼────┐
             │    X    │
             │ Flash   │
             │ 64 MB   │
             └─────────┘
Enter fullscreen mode Exit fullscreen mode

Then:

Cartridge A
→ robot software

Cartridge B
→ CNC software

Cartridge C
→ sensor software

Cartridge D
→ test software
Enter fullscreen mode Exit fullscreen mode

The same physical UNO can therefore become different devices depending on the inserted cartridge.

This is essentially a programmable embedded platform + application cartridge architecture.


32. Hot-Swap Consideration

The physical cartridge should not simply be pulled while the MCU is actively communicating with it.

A safer design is:

Running
   ↓
Request shutdown
   ↓
Save state
   ↓
Disable SPI
   ↓
Confirm safe
   ↓
Power/cartridge removal
Enter fullscreen mode Exit fullscreen mode

For an experimental prototype, swapping while the device is powered off is much simpler.


33. Advantages

The architecture provides several major benefits.

Large application repository

You can store many modules in X.

Modular development

Different functionality can be developed separately.

OTA

Modules can be downloaded without necessarily replacing the entire conceptual application repository.

Cartridge capability

The same physical MCU can host different software collections.

Recovery

A known-good module can remain available.

Feature packs

Optional functionality can be installed without permanently occupying active execution space.

Product customization

Different customers could receive different modules.


34. Disadvantages

The system also creates substantial complexity.

Switching latency

Loading and programming take time.

Flash wear

Repeatedly rewriting the same internal Flash blocks consumes their erase/program budget.

RAM limitation remains

Large external storage does not create more SRAM.

State management

The system needs a clean persistent-state design.

Compatibility

Module/runtime versioning must be controlled.

Recovery complexity

A failed update must not brick the device.

Development complexity

A custom loader, module format, build pipeline, and update protocol are required.


35. Best Use Cases

This architecture is especially attractive for:

Application Suitability
Sensor controller Excellent
Automation system Excellent
Robot with optional modes Excellent
Educational platform Excellent
Diagnostic instrument Excellent
Configuration-driven machine Excellent
Modular IoT device Excellent
OTA feature system Excellent
Large menu-driven embedded application Good
Audio/visual device Depends
Real-time motor control Hybrid architecture recommended
High-throughput server Poor
Ultra-low-latency networking Poor
Large multitasking OS Poor

36. Theoretical Scaling

Suppose X is:

128 MB
Enter fullscreen mode Exit fullscreen mode

and each module is:

200 KB
Enter fullscreen mode Exit fullscreen mode

Ignoring filesystem and metadata overhead:

128 MB / 200 KB
≈ 655 modules
Enter fullscreen mode Exit fullscreen mode

That does not mean 655 modules can execute simultaneously.

It means approximately 655 modules can be stored.

The active MCU still only has room for the current module.


37. Example Full System

Suppose a machine contains:

100 modules
Enter fullscreen mode Exit fullscreen mode

with an average compiled size of:

150 KB
Enter fullscreen mode Exit fullscreen mode

Total repository:

100 × 150 KB
= 15 MB
Enter fullscreen mode Exit fullscreen mode

The RA4M1 may only need enough program Flash for:

Permanent runtime
+
loader
+
one active module
Enter fullscreen mode Exit fullscreen mode

The remaining application library lives externally.

This is exactly the fundamental advantage of your approach.


38. Why the Idea Is Not "Infinite Code"

It is important to describe the system accurately.

Your architecture does not provide:

unlimited executable code.

It provides:

a very large externally stored program composed of sequentially or conditionally loaded executable modules.

The distinction matters.

For example:

Traditional:
256 KB available
→ application must fit concurrently

Modular:
256 KB active execution envelope
+
128 MB external module repository
Enter fullscreen mode Exit fullscreen mode

That is a very significant capability increase, but it is not equivalent to having 128 MB of directly executable internal memory.


39. Potential Future Upgrade

The concept can become much more powerful if implemented on an MCU/platform with genuine external execute-in-place capability or a memory-mapped high-speed external memory interface.

The RA4M1 used on the UNO R4 WiFi does not provide a QSPI/OSPI or external memory bus, which makes load-into-internal-Flash the more appropriate design on this particular board.

A future custom board could instead use an MCU specifically designed for:

External Flash
      ↓
memory-mapped execution
      ↓
CPU
Enter fullscreen mode Exit fullscreen mode

That would potentially eliminate or greatly reduce the need to copy every module into internal Flash.

This is an important distinction between:

"external storage"

and

"external executable memory."


40. Recommended Prototype

A sensible first prototype would be intentionally small.

Hardware

UNO R4 WiFi
+
SPI NOR Flash breakout
Enter fullscreen mode Exit fullscreen mode

or:

UNO R4 WiFi
+
microSD module
Enter fullscreen mode Exit fullscreen mode

Software

Create:

Permanent loader
Module A
Module B
Module C
Enter fullscreen mode Exit fullscreen mode

Module A:

Turn LED ON
Wait
Save state
Request Module B
Enter fullscreen mode Exit fullscreen mode

Module B:

Read state
Turn LED OFF
Wait
Request Module C
Enter fullscreen mode Exit fullscreen mode

Module C:

Read state
Finish
Enter fullscreen mode Exit fullscreen mode

Then measure:

T_transfer
T_erase
T_program
T_verify
T_reset
T_total
Enter fullscreen mode Exit fullscreen mode

This experiment will reveal the actual performance rather than relying on theoretical estimates.


41. Recommended Development Path

Stage 1 — Prove external storage

Successfully:

RA4M1 → SPI → X
Enter fullscreen mode Exit fullscreen mode

and read/write arbitrary data.

Stage 2 — Firmware package format

Implement:

header
version
size
CRC
signature
Enter fullscreen mode Exit fullscreen mode

Stage 3 — Boot/recovery loader

Create:

loader
   ↓
select module
   ↓
program
   ↓
verify
   ↓
boot
Enter fullscreen mode Exit fullscreen mode

Stage 4 — Persistent state

Implement:

module → state → next module
Enter fullscreen mode Exit fullscreen mode

Stage 5 — Multi-module application

Move from a 3-module demonstration to a real application.

Stage 6 — OTA

Use:

ESP32-S3
   ↓
Wi-Fi
   ↓
download
   ↓
X
   ↓
RA4M1
Enter fullscreen mode Exit fullscreen mode

Stage 7 — A/B recovery

Implement automatic rollback.

Stage 8 — Security

Add:

signature verification
anti-rollback/version rules
encrypted transport
Enter fullscreen mode Exit fullscreen mode

42. Final Architecture

The resulting system could look like this:

                         INTERNET
                            │
                            │ Wi-Fi
                            ▼
                     ┌─────────────┐
                     │  ESP32-S3   │
                     │             │
                     │ Wi-Fi       │
                     │ OTA client  │
                     │ Cloud/API   │
                     └──────┬──────┘
                            │
                     module/update data
                            │
                            ▼
                     ┌─────────────┐
                     │      X      │
                     │             │
                     │ Module 001  │
                     │ Module 002  │
                     │ Module 003  │
                     │ ...         │
                     │ OTA         │
                     │ Backup      │
                     │ State       │
                     └──────┬──────┘
                            │
                           SPI
                            │
                            ▼
                  ┌─────────────────────┐
                  │       RA4M1         │
                  │                     │
                  │ Permanent runtime   │
                  │ Module loader       │
                  │ State manager       │
                  │ Active module       │
                  │ Real-time control   │
                  └─────────────────────┘
Enter fullscreen mode Exit fullscreen mode

43. Overall Technical Assessment

The core idea is technically viable.

The strongest interpretation of the idea is not:

"Make the Arduino have unlimited Flash."

It is:

Build a modular embedded execution platform where a small resident runtime loads independently packaged application modules from a much larger external storage repository.

For the UNO R4 WiFi specifically, the most practical first implementation is:

RA4M1
+
SPI external NOR Flash / microSD
+
custom module loader
+
persistent state
+
A/B recovery
+
ESP32-S3 OTA subsystem
Enter fullscreen mode Exit fullscreen mode

The principal constraints are:

Internal Flash capacity
        +
32 KB SRAM
        +
module-switching latency
        +
internal Flash endurance
        +
module compatibility/state management
Enter fullscreen mode Exit fullscreen mode

The biggest performance issue is not simply reading X. It is the time and wear involved in erasing/programming the RA4M1's internal code Flash. Renesas' published Flash timings show why a large module can take substantially longer to activate than its SPI transfer time alone suggests.


44. Final Conclusion

Your original theory has a solid engineering basis.

A very large application can be decomposed into modules:

Huge application
       ↓
many compiled modules
       ↓
large external X
       ↓
small permanent runtime
       ↓
one active module at a time
Enter fullscreen mode Exit fullscreen mode

This can effectively separate:

total stored application size

from

active executable size.

For sequential and modular embedded applications, this can be extremely useful.

For latency-sensitive or highly concurrent applications, the architecture should instead use a hybrid model, keeping the critical runtime permanently resident and using X only for optional or infrequently used functionality.

The next major improvement beyond this concept would be designing a real module runtime/ABI that allows several modules to coexist without replacing the entire application Flash each time. That would move the project from a simple firmware-loader experiment toward a genuine miniature embedded operating environment.

Top comments (0)