Anyone who has tinkered with Arduino is familiar with the successful upload dialog that indicates your code has successfully loaded on to your hardware. Part of that message, which I hardly paid attention to until recently, indicates how much storage space your code occupies.
For the majority of code that the majority of users, space won't ever be a problem - until it is. I knew, in theory, that this could be a problem, but until recently I have not been using so many different types of hardware, and had never encountered this issue.
Why does this happen, and how is memory even stored on the hardware to begin with!? In this article, I will walk you through microcontroller memory and storage in lay-terms, so even a beginner to Arduino can understand how their code is stored on their hardware, and what to do when it doesn't fit! For the sake of simplicity I will discuss the Arduino Uno, but the same principles can be extended to other microcontroller development boards.
Where is Code Stored?
The Arduino Uno, which utilizes the ATmega 328 chip, has two distinct types of memory - data memory (SRAM) and program memory (FLASH). The ATmega 328 has 32K bytes of flash, and 2K bytes of SRAM. Additionally, a third type of memory, EEPROM, exists on the Arduino Uno; it can only be written and read byte-by-byte and is often used for long-term data storage and on the Uno there is only 1K bytes of EEPROM. Let's discuss each one more in-depth.
Flash memory, or program memory, is where your program and initializing data is stored. This code cannot be modified by your program, only by you. When the Arduino uploads from the Arduino IDE and tells you the amount of space utilized, it is the flash, or program memory to which it is referring.
"Sketch uses , 24,888 bytes (86%) of program memory storage space Maximum is 28,672 bytes."
Flash memory is non-volatile, which means it won't be erased when you power down - just like your thumb drive. With a finite lifetime of about 100,000 write cycles, so you will likely never reach flash memory failure. About 0.5K bytes are consumed by the bootloader, so you really only have about 31.5K bytes of flash memory to dedicate to your program, which isn't very much!
Static Random Access Memory (SRAM)
Any data generated by your program is copies into static random access memory, or SRAM. Unlike Flash, SRAM is volatile which means it is only temporary storage of data, and each time you restart your device, the SRAM is wiped clean.
Types of data that are stored in SRAM include static and global variables declared in your program, local variables, a record of interrupts, and a record of function calls. It also stores all the strings you use in your program, which can take up space very quickly.
Your compiler doesn't tell you what the SRAM usage is on each upload of your code, so you have to seek it out. The function "freeMemory()" can be used to determine the relative amount of SRAM unused in your program, and its library can be downloaded on Michael P. Flaga's github here. Adafruit does great job of diving into greater detail in the use and allocation of SRAM memory, and if you're itching for more detail, I highly suggest their entire Arduino Memory Guide.
The EEPROM is like a teeny, tiny hard drive. Like Flash memory it is non-volatile, so it is not erased during a power cycle. This makes it a great place to store long-term data - but not much of it, as there is only slightly more than 1K of EEPROM available on the Arduino Uno. EEPROM is similar to Flash in that is has 100,000 write-cycle lifetime, but it can be read as many times as you'd like.
Another difference between EEPROM and Flash and SRAM, is that data is only written into EEPROM if directed to do so by the user (EEPROM.write), so unless you are purposefully directing data there, you won't ever run into any EEPROM memory problems.
How is Code Stored?
Now that we understand the types of memory in our Arduino, how is this information stored to begin with? What physical entities give rise to the three different types of electronic memory? To answer these questions we have to start at the very basics. StratifyLabs did an amazing job of walking through embedded design basics, for more detail on this topic visit their website.
Semiconductors are materials that exist in the middle ground between insulators and and conductors. WIthout delving into the physics, a semiconductor's atomic properties allow the flow and direction of electricity to be controlled. Semiconductor materials are the key materials in many electrical components including diodes and transistors.
The heart of all modern computing is the transistor, which is essentially a voltage-controlled switch that can also be used for amplifying a voltage or current, or as a switch. The concept of a transistor as a switch is helpful in understanding how information is stored on microcontrollers. A switch can either be on or off; in computing we call on=1 and off=0. You may have seen I/O on your desktop power switches before. By using transistors we can code information as 1's and 0's.
The Binary Code
Computers store information as numbers - specifically only the numbers 1 and 0. Unlike the traditional base-10 number system that we deal with every day (1, 2, 3, 4, 5, 6, 7, 8, 9, 0), also called the decimal system, the base-system used by computers utilizes only two numbers - 1 and 0. This base-2 number system used by computers is called the binary code. By storing information as a series of 1 and 0's, the data can easily be encoded by transistor switches that are either on (1) or off (0).
There are basic conversions between base-10 numbers are base-2 numbers, as seen in the table below. Additionally, there are base-2 representations for letters and mathematical operations which are represented by a base-10 number which is then coded into binary; this base-10 letter and symbol code is called ASCII. Claude Shannon used these representations in his master's thesis in 1937 to show that all information can be encoded using binary. This became important in the advent of electrical switches, which could then be used to represent and store that information!
Each singular 1 or zero is called a bit. Eight of these bits together form one byte. In the chart above, this means that the number "4" in base-10 can be encoded in 0.5 bytes. Because everything is encoded by a pattern of 1's and 0's, the building of multiple bits can encode more and more information. The table below shows for a given number of bits, how many individual patterns can be formed using that number of bits.
Number of Bits Number of Different Patterns
1 0 1
2 00 01 10 11
3 000 001 010 011 100 101 110 111
For every additional bit, you can double the number of individual patterns. This means, that for one byte (8 bits) there are 256 different patterns you can make!
To Be Continued...
Anthes, Gary. “Binary Basics.” Computerworld, Computerworld, 26 Mar. 2007, www.computerworld.com/article/2553322/computer-hardware/binary-basics.html.
Earl, Bill. “Memories of an Arduino.” You Know You Have a Memory Problem When... | Memories of an Arduino | Adafruit Learning System, Adafruit Industries, learn.adafruit.com/memories-of-an-arduino/you-know-you-have-a-memory-problem-when-dot-dot-dot.
IBM. “ASCII, Decimal, Hexadecimal, Octal, and Binary Conversion Table.” Asynchronous Adapters, IBM Knowledge Center, www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.networkcomm/conversion_table.htm.
Stanford. “Bits and Bytes.” CS 101, Stanford, web.stanford.edu/class/cs101/bits-bytes.html.