Technical Article

Embedded Firmware Tips and Tricks: Use Your Read Only Memory to Free Up RAM

September 16, 2019 by Robert Keim

Learn how to use code memory to free up RAM on your MCU.

This article gives you some ideas on how to make the most of your MCU’s (often overabundant) nonvolatile storage.

There must be engineers out there who regularly need a significant portion of the 16, 32, or even 64 kB of program memory provided by 8-bit microcontrollers. Surely the manufacturers would not include so much code space if designers didn’t need it.

What I can say with confidence is that I have never felt constrained by the amount of program memory in an MCU. I have, however, felt constrained by the amount of data memory, and the purpose of this article is to explain how you can use your excess code memory to free up some RAM.


What Is Read-Only Memory? (AKA Code Memory, AKA Program Memory)

Microcontroller memory is divided into categories that correspond to electrical characteristics (e.g., volatile vs. nonvolatile) and architectural factors, such as the 8051’s distinction between internal data memory and “external” data memory (the external RAM can, somewhat confusingly, be included on-chip). For example:


The MSP430 memory structure. Diagram courtesy of Texas Instruments.


Code memory, AKA program memory or read-only memory (ROM), is where the program’s instructions are stored. We also call this “the flash” because nowadays code memory is implemented using a nonvolatile storage technology known as flash memory.

An important thing to understand about a microcontroller’s read-only memory is that it’s not read-only memory. First of all, if it were truly “read-only,” it would be worthless because the MCU’s programmer hardware wouldn’t be able to write program instructions into it. More importantly, MCUs allow you to write to this memory from within your firmware. Thus, it is actually readable, writable, nonvolatile memory that you can use for general data storage.

(Note: I believe that the ability to write to code memory from firmware is fairly standard nowadays, but if you’ve come across a modern microcontroller that doesn’t support this functionality, let us know in the comments section below.)


Note! Don’t Use It Unless You Have To

Before I go any further I want to be clear on this point: when you’re working with data that must be stored during program operation, code memory is a last-resort replacement for RAM.

Accessing RAM is faster, and in my experience, the procedure required to write to code memory during firmware execution is complicated and entails the risk of corrupting the flash.

Don’t use code memory for storing variables and arrays that require frequent modification—these should be in data memory.

If your MCU doesn’t have enough RAM for all of your frequently modified variables, use a different MCU or add an external memory chip.


Pre-Runtime Storage

The better way to supplement RAM using code memory involves the storage of constant values. These could be many different things: display patterns that you will send to an LCD module, fixed byte or character sequences that will be transmitted via SPI or UART, precalculated sine-wave values that will be used to generate different audio frequencies via digital-to-analog conversion, and so forth.

Storing constant values in flash instead of RAM is easy because you simply include the values in your firmware (as normal variables or arrays) and tell the compiler that you want them stored in code memory. With my compiler, all I need to do is place the keyword “code” before the variable name (see below for an example); your compiler might be different.

unsigned char code UART_Message[4] = {0xAA, 0xAA, 0x1C, 0x2D};

Code memory is sometimes so abundant that this technique could be used for storing some sort of basic image or a brief digitized audio clip.


Runtime Storage

Runtime storage is the more complicated way to use code memory as a RAM replacement. You’ll have to consult your MCU’s datasheet, or maybe even a relevant app note, to find the required procedure and learn about potential problems. For example, the following diagram conveys information about flash-write procedures for 16-bit PIC microcontrollers:


Diagram courtesy of Microchip.


Runtime code-memory storage is useful for saving calibration values that are generated during device operation. In this case the primary advantage is the fact that code memory is nonvolatile, since these types of data generally won’t consume much RAM. An example of a situation in which runtime code-memory storage would help you to cope with RAM limitations is if you need to record a long sequence of measurement values that are gathered once and then left alone until an operator downloads the measurements to a PC.



For those who, like me, are much more likely to run out of RAM before they run out of flash, program memory is a valuable resource because it may allow you to meet system requirements while using a smaller microcontroller and eliminating the complexity and cost of incorporating an external memory chip.

If you have any tips for writing to flash (during runtime) with your preferred microcontroller family, feel free to share them in the comments section.


Featured image is used courtesy of Steve Jurvetson via the CC BY 2.0 license. The resized photo is of a historical core memory board on display in Adafruit's Core Memory Room.

  • Analog Ground September 18, 2019

    A caution. One issue with using flash memory is write endurance. For example, I am currently working with an NXP micro-controller and the worst case, minimum number of write cycles for the flash is 10,000 cycles. I was part of a project where some calibration values needed to be updated about once a day. No big deal. However, the programmer was new to embedded and it made his code simpler to update once a second. The flash failed after a few days.

    Like. Reply