{"id":17307,"date":"2023-02-03T20:30:25","date_gmt":"2023-02-03T20:30:25","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/?p=17307"},"modified":"2024-11-27T08:37:15","modified_gmt":"2024-11-27T08:37:15","slug":"sram-management","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management","title":{"rendered":"SRAM Management"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">About this post<\/h2>\n\n<p>In this article, we will dive into the depths of SRAM (Static Random Access Memory). In doing so, I will explain the difference between stack and heap and show how variables are created and managed in these memory areas. In this context, we will also address the question of why one should be careful when using strings in Arduino sketches. Finally, I&#8217;ll give you some tips on how to use the SRAM resource sparingly.<\/p>\r\n<p>All this is not new, and there are already quite a few good articles about it on the web. I think what sets this post apart from many others is the level of detail and the approach. Above all, I want to show very concretely on address level what is going on in the SRAM when different variables are created. I will also show you how to determine the addresses of variables in the heap. &#8220;Forensic Arduinoistics,&#8221; so to speak.<\/p>\r\n<p>The article assumes basic knowledge about pointers, references and the address operator. If you have difficulties with this, please read my last post.<\/p>\r\n<p>What topics I will cover:<\/p>\r\n<ol>\r\n<li><a href=\"#flash_sram_eeprom\">Flash, SRAM and EEPROM<\/a><\/li>\r\n<li><a href=\"#sram_overview\">The SRAM at a glance<\/a><\/li>\r\n<li><a href=\"#variable_storage_in_sram\">How variables are stored in SRAM<\/a><\/li>\r\n<li><a href=\"#stack_management\">Stack Management<\/a><\/li>\r\n<li><a href=\"#string_handling_in_sram\">String handling in SRAM<\/a>\r\n<ol>\r\n<li><a href=\"#string_analysis_in_stack_and_heap\">String analysis in stack and heap<\/a><\/li>\r\n<li><a href=\"#heap_fragmentation\">Heap fragmentation <\/a><\/li>\r\n<li><a href=\"#string_concatenation\">Concatenating strings<\/a><\/li>\r\n<li><a href=\"#should_i_use_strings\">So, should I use strings or not?<\/a><\/li>\r\n<\/ol>\r\n<\/li>\r\n<li><a href=\"#character_arrays\">Character Arrays<\/a><\/li>\r\n<li><a href=\"#move_variables_to_heap\">Force variables into the heap<\/a><\/li>\r\n<li><a href=\"#save_progmem\">Saving SRAM with PROGMEM and F()<\/a><\/li>\r\n<\/ol>\r\n\n<h2 class=\"wp-block-heading\" id=\"flash_sram_eeprom\">1. Flash, SRAM and EEPROM <\/h2>\n\n<h3 class=\"wp-block-heading\">1.1. Overview<\/h3>\n\n<p>The design of the memory of a microcontroller depends on the model. In this article, I mainly refer to the ATmega328P, which is used for example in the Arduino UNO, Nano and Pro Mini.<\/p>\r\n<p>As you can see in the diagram on the right, the ATmega328P has three different memoriy areas, namely the relatively large <strong>flash<\/strong>, the <strong>SRAM<\/strong> and the <strong>EEPROM<\/strong>.<\/p>\r\n<p>Even though the memory design of other microcontrollers differ quite a bit (see table below), the SRAM is comparatively smaller in all of them compared to the flash and is thus a resource worth protecting.&nbsp;<\/p>\r\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples-1024x326.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"326\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples-1024x326.png\" alt=\"Memory of different microcontrollers\" class=\"wp-image-16978\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples-1024x326.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples-300x95.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples-768x244.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/mcu_memory_examples.png 1167w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Memory of different microcontrollers<\/figcaption><\/figure>\n\n<p>The <strong>flash<\/strong> is also called program memory. When you upload your sketches, they are first compiled, then translated into machine-readable code, and finally written to flash. The bootloader is also located there. The flash is non-volatile, i.e. the memory content is retained even when the MCU is disconnected from the supply voltage. Moreover, it does not change during program execution, so there are no runtime problems with it.<\/p>\r\n<p>The <strong>EEPROM<\/strong> is also non-volatile. I have described it in detail in <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/eeprom-part-1-avr-internal-eeproms\" target=\"_blank\" rel=\"noopener\">this post<\/a>. It is particularly well suited for data that may change during the runtime, but on the other hand should be permanently preserved. This could be, for example, calibration factors for sensors or data from the last program run.&nbsp;<\/p>\r\n<p>The <strong>SRAM<\/strong> is your working memory. It is reserved for the variables of your programs. One of the challenges in dealing with the SRAM is that its occupancy rate can only be planned to a limited extent.<\/p>\r\n\n<h3 class=\"wp-block-heading\">1.2. Memory usage details during sketch upload<\/h3>\n\n<p>When you upload your sketches to your microcontroller via the Arduino IDE, you will get an info like the following:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/arduino_mem_info.png\"><img loading=\"lazy\" decoding=\"async\" width=\"977\" height=\"79\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/arduino_mem_info.png\" alt=\"Memory usage details during sketch upload\" class=\"wp-image-16983\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/arduino_mem_info.png 977w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/arduino_mem_info-300x24.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/arduino_mem_info-768x62.png 768w\" sizes=\"auto, (max-width: 977px) 100vw, 977px\" \/><\/a><figcaption class=\"wp-element-caption\">Memory usage details during sketch upload.<\/figcaption><\/figure>\n\n<p>In this example, the program uses 9716 bytes of the <em>available<\/em> flash, or: 31% of 30720 bytes. Actually, 32 KB of flash are available, the difference is due to the bootloader. 2048 bytes of SRAM are available. Of these, the sketch uses 751 bytes (36%) for global variables. This value is known at compile time and does not change during runtime. Local variables, on the other hand, &#8220;come and go.&#8221; How many of them are &#8220;alive&#8221; at any given time and how much space they require cannot necessarily be predicted.<\/p>\r\n\n<h3 class=\"wp-block-heading\">1.3. Static and dynamic &#8211; confusing terms<\/h3>\n\n<p>RAM is the generic term for SRAM (Static RAM) and DRAM (Dynamic RAM). SRAM and DRAM differ in their physical structure. SRAM is considerably more expensive, but also faster and more power-efficient. Mostly, SRAM is used in microcontrollers. More information about the differences between SRAM and DRAM can be found <a href=\"https:\/\/www.diffen.com\/difference\/Dynamic_random-access_memory_vs_Static_random-access_memory\" target=\"_blank\" rel=\"noopener\">here<\/a>, for example.&nbsp;<\/p>\r\n<p>In the ESP32 documentation, the term DRAM is used for Data RAM to distinguish it from IRAM, the Instruction RAM (see <a href=\"https:\/\/docs.espressif.com\/projects\/esp-idf\/en\/latest\/esp32\/api-reference\/system\/mem_alloc.html#memory-capabilities\" target=\"_blank\" rel=\"noopener\">here<\/a>). So, it is not a physical difference, but a functional one.<\/p>\r\n<p>Sometimes the SRAM is also called dynamic memory &#8211; for example in the Arduino IDE, as we have just seen. Still others mean only the heap when they talk about dynamic memory.<\/p>\r\n<p>And to complete the confusion, the global variables and the static local variables are called &#8220;Static Data&#8221;, which are stored in a specific area of the SRAM.<\/p>\r\n<p>I will therefore try to avoid the terms &#8220;static&#8221; and &#8220;dynamic&#8221; as far as possible. &nbsp;<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"sram_overview\">2. The SRAM at a glance<\/h2>\n\n<p>In my previous remarks I did not mention the memory area for the registers because it is not available for free use. It is located below the SRAM and is the reason why the memory addresses do not start at zero, but in the case of the ATmega328P at 256:<\/p>\r\n<div class=\"wp-block-image is-resized\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P-1024x475.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"475\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P-1024x475.png\" alt=\"The SRAM of the ATmega328P\" class=\"wp-image-16985\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P-1024x475.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P-300x139.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P-768x356.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/data_memory_atmega328P.png 1101w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">The SRAM of the ATmega328P<\/figcaption><\/figure>\n<\/div>\nIn the lower area of the SRAM, the already mentioned static data or variables are stored. All other variables are either in the stack or in the heap.\u00a0 The stack is filled from top to bottom, and the heap from bottom to top. If there is not enough memory, the two areas collide (without error message!). In this case, the program will no longer function as desired. However, it is not possible to predict what the specific impact will be.\r\n\r\nForget for a moment the fact that the stack &#8220;hangs from the ceiling&#8221; like a stalactite and imagine it like a stack of books. There are no gaps due to gravity. New books (e.g. when functions are called) are placed on top of the book stack and taken down again from there (return from the function). Thanks to systematic planning, no books have to be pulled out of the middle or bottom of the book stack. It&#8217;s the same with the stack memory, except that the world is upside-down.\r\n\r\nWhen you remove a book from a stack, the gap is filled due to gravity. New books will be placed on top of the pile. It is the same with the stack, except that the world is upside-down.\r\n\r\nA heap is less orderly than a stack &#8211; in this respect, the naming of the heap fits well. However, I would describe the heap more as a kind of bookshelf that you (first-)fill strictly from the bottom up. If you take out a book, there will be a gap. Then, when you put a new one in, it will rarely be the same size. If it is smaller, then it will fit in the gap, but the gap will not be completely filled. If, on the other hand, it is larger, it will have to be placed on the top. So, the books are not pushed together to eliminate gaps. And if you don&#8217;t do something about it, more and more space on your bookshelf will go unused over time.\r\n\r\nThis problem is called heap fragmentation. In practice, it occurs mainly when string objects are used. But we&#8217;ll look at that in more detail shortly, step by step and with practical examples.\n\n<h2 class=\"wp-block-heading\" id=\"variable_storage_in_sram\">3. How variables are stored in the SRAM<\/h2>\n\n<h3 class=\"wp-block-heading\">3.1. Example sketch<\/h3>\n\n<p>In the first example sketch, we create a motley assortment of variables, and we show where they can be found in the SRAM.<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_1.ino\" data-enlighter-title=\"example_1.ino\">int a = 42;\r\nint b = 43;\r\nint c = 44;\r\n\r\nvoid setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n    int d = 45;\r\n    int e = 46;\r\n    int f = 47;\r\n    char g[] = \"I am a char array\";\r\n    char h[] = \"I am a char array, too\";\r\n    char i[] = \"No surprise what I am\";\r\n    String j = \"I am a string\";\r\n    String k = \"I am a string, too\";\r\n    String l = \"Guess what I am\";\r\n\r\n    Serial.println(F(\"Addresses in SRAM:\"));\r\n    \r\n    Serial.print(F(\"a (int, global): \"));\r\n    printVariableDetails(a);   \r\n    \r\n    Serial.print(F(\"b (int, global): \"));\r\n    printVariableDetails(b);  \r\n    \r\n    Serial.print(F(\"c (int, global): \"));\r\n    printVariableDetails(c);  \r\n    \r\n    Serial.print(F(\"d (int, local): \"));\r\n    printVariableDetails(d);  \r\n     \r\n    Serial.print(F(\"e (int, local): \"));\r\n    printVariableDetails(e);  \r\n    \r\n    Serial.print(F(\"f (int, local): \"));\r\n    printVariableDetails(f);  \r\n    \r\n    Serial.print(F(\"g (char array): \"));\r\n    Serial.print((int)&amp;g);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println((int)&amp;g + sizeof(g) - 1);\r\n    \r\n    Serial.print(F(\"h (char array): \"));\r\n    Serial.print((int)&amp;h);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println((int)&amp;h + sizeof(h) - 1);\r\n    \r\n    Serial.print(F(\"i (char array): \"));\r\n    Serial.print((int)&amp;i);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println((int)&amp;i + sizeof(i) - 1);\r\n    \r\n    Serial.print(F(\"j (String): \"));\r\n    printVariableDetails(j); \r\n    \r\n    Serial.print(F(\"k (String): \"));\r\n    printVariableDetails(k); \r\n    \r\n    Serial.print(F(\"l (String): \"));\r\n    printVariableDetails(l); \r\n}\r\n\r\nvoid loop() {}\r\n\r\ntemplate&lt;typename T&gt;\r\nvoid printVariableDetails(T &amp;i){\r\n    Serial.print((int)&amp;i);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println((int)&amp;i + sizeof(i) - 1);\r\n}\r\n\r\n\/* For those who are not familiar with templates: \r\n * If you have functions to which you want to pass different data types or which shall \r\n * return different variable types, you can use templates to avoid defining several functions\r\n * for each data type like:\r\n * void printVariableDetails(int &amp;i){.....}\r\n * and:\r\n * void printVariableDetails(String &amp;i){.....}\r\n *\/<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>Here is the output on an Arduino Nano:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"381\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_1.png\" alt=\"example_1.ino - output when using an Arduino Nano\" class=\"wp-image-16903\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_1.png 731w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_1-300x156.png 300w\" sizes=\"auto, (max-width: 731px) 100vw, 731px\" \/><\/a><figcaption class=\"wp-element-caption\">example_1.ino &#8211; output when using an Arduino Nano<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">3.2. Review of example_1.ino<\/h3>\n\n<p>What we can conclude from this:<\/p>\r\n<ul>\r\n<li>Using the example of the integer variables a, b and c, we can see that global variables are stored at the bottom of the stack (&#8220;Static Data&#8221; area). On an ATmega328P based board, integer variables occupy two bytes each.\r\n<ul>\r\n<li>The integer values are representative of simple variable types in this sketch. In the same way, we could have taken variables of type long, float, double, and so on.<\/li>\r\n<\/ul>\r\n<\/li>\r\n<li>The order of the variable addresses does not necessarily correspond to the order in which the variables are defined.<\/li>\r\n<li>In the setup we define three more integer variables, namely d, e and f. However, they are on the stack, i.e. at the top of the SRAM because they are local variables.<\/li>\r\n<li>The character arrays g, h and i are also located in the stack. Their space requirement corresponds to the number of their characters plus an extra byte for the null character (ASCII character 0 = &#8216;\\0&#8217;, also call null terminator).<\/li>\r\n<li>Finally, we defined the strings j, k and l. More precisely, we have created objects of the string class. They require 6 bytes each in the stack, regardless of their length. At least this is true for the AVR based Arduinos.<\/li>\r\n<\/ul>\r\n<p>The last point may be surprising, especially since I had already anticipated that strings occupy memory space in the heap. The solution is: A string object consists of two parts. The actual string is located in the heap. In the stack, however, only a kind of reference to the string object is created, which consists of three components (the string variable, so to speak):<\/p>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">char *buffer;\t        \/\/ the actual char array\r\nunsigned int capacity;  \/\/ the array length minus one (for the '\\0')\r\nunsigned int len;       \/\/ the String length (not counting the '\\0')<\/pre>\r\n\n<p>The first two bytes of the string variable represent the pointer to the string (&#8220;buffer&#8221;) located in the heap. This is followed by an integer value which is the amount of memory reserved for the string (&#8220;capacity&#8221;). This is followed by an integer value containing the actual length of the string (&#8220;len&#8221;). Take it that way for now, I&#8217;ll come back to it in a minute.&nbsp;<\/p>\r\n<p>By the way, you can find the definition of the class String in the depths of the Arduino library files in WString.h: &#8230;\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\<em>version<\/em>\\cores\\arduino\\WString.h (with version = version number).<\/p>\r\n\n<h3 class=\"wp-block-heading\">3.3. example_1.ino on other MCUs<\/h3>\n\n<p>The sketch example_1 is also executable on other boards without any changes. I tested it on a Nano Every, Mega2560, ESP32, Nano 33 IoT and a Wemos D1 Mini (ESP8266).<\/p>\r\n<p>Here is the output on an ESP32:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/02\/output__example_1_esp32.png\"><img loading=\"lazy\" decoding=\"async\" width=\"761\" height=\"381\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/02\/output__example_1_esp32.png\" alt=\"\" class=\"wp-image-19977\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/02\/output__example_1_esp32.png 761w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/02\/output__example_1_esp32-300x150.png 300w\" sizes=\"auto, (max-width: 761px) 100vw, 761px\" \/><\/a><figcaption class=\"wp-element-caption\">example_1.ino &#8211; Output when using an ESP32<\/figcaption><\/figure>\n\nAs you can see, the memory of the ESP32 is organized differently. Heap and stack also exist, but the distance between the highest address used and the lowest is: 1073500571 &#8211; 1073470312 = 30259, which is only about a tenth of the available working memory. Also, a string requires 16 bytes in the stack. This is not least because the addresses on the ESP32 are 4 bytes in size. The definition of the class String for the ESP32 can be found here: &#8230;\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\<em>version<\/em>\\cores\\esp32\\WString.h.\r\n\r\nIf you are interested in the details of the ESP32 memory in general, I recommend <a href=\"https:\/\/blog.espressif.com\/esp32-programmers-memory-model-259444d89387\" target=\"_blank\" rel=\"noopener\">this article<\/a>.\n\n<h2 class=\"wp-block-heading\" id=\"stack_management\">4. Stack management<\/h2>\n\n<h3 class=\"wp-block-heading\">4.1. Example sketch<\/h3>\n\n<p style=\"text-align: left;\">With the next sketch, I want to show that the memory for variables in the stack that are no longer needed is automatically freed. In other words, you don&#8217;t have to worry about stack management!<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_2.ino\" data-enlighter-title=\"example_2.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n\r\n    int a = 1111;\r\n    Serial.print(F(\"a: \"));\r\n    Serial.print((int)&amp;a);\r\n    Serial.println(F(\" (setup)\"));\r\n    Serial.println();\r\n    \r\n    function_1();\r\n    Serial.println();\r\n    \r\n    int c = 3333;\r\n    Serial.print(F(\"c: \"));\r\n    Serial.print((int)&amp;c);\r\n    Serial.println(F(\" (setup)\"));\r\n    Serial.println();\r\n    \r\n    function_2();\r\n    Serial.println();\r\n    function_3();\r\n}\r\n\r\nvoid loop() {}\r\n\r\nvoid function_1(){\r\n    int b = 2222;\r\n    Serial.print(F(\"b: \"));\r\n    Serial.print((int)&amp;b);\r\n    Serial.println(F(\" (function_1)\"));\r\n}\r\n\r\nvoid function_2(){\r\n    int d = 4444;\r\n    Serial.print(F(\"d: \"));\r\n    Serial.print((int)&amp;d);\r\n    Serial.println(F(\" (function_2)\"));\r\n    function_2a();\r\n}\r\n\r\nvoid function_2a(void){\r\n    int e = 5555;\r\n    Serial.print(F(\"e: \"));\r\n    Serial.print((int)&amp;e);\r\n    Serial.println(F(\" (function_2a)\"));\r\n    function_2b();\r\n}\r\n\r\nvoid function_2b(void){\r\n    int f = 6666;\r\n    Serial.print(F(\"f: \"));\r\n    Serial.print((int)&amp;f);\r\n    Serial.println(F(\" (function_2b)\"));\r\n}\r\n\r\nvoid function_3(void){\r\n   int g = 7777;\r\n    Serial.print(F(\"g: \"));\r\n    Serial.print((int)&amp;g);\r\n    Serial.println(F(\" (function_3)\"));\r\n    function_3a();\r\n    \r\n}\r\n\r\nvoid function_3a(void){\r\n    int h = 8888;\r\n    Serial.print(F(\"h: \"));\r\n    Serial.print((int)&amp;h);\r\n    Serial.println(F(\" (function_3a)\"));\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>Here is the output for an Arduino Nano (ATmega328P):<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"381\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_2.png\" alt=\"Output from example_2.ino\" class=\"wp-image-16907\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_2.png 732w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_2-300x156.png 300w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of example_2.ino (Arduino Nano)<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">4.2. Review of example_2.ino<\/h3>\n\n<p>The variables a and c &#8220;survive&#8221; as long as the setup is executed. All other variables exist only within their functions and &#8220;die&#8221; after returning to the setup. The memory space is reused. Since function 2 calls function 2a, which in turn calls function 2b, the variables d, e, and f coexist. The same applies to g and h.<\/p>\r\n<p>&#8220;Homework&#8221;: prefix one of the integer definitions with &#8220;static&#8221;. So, for example: <code>static int d = 4444;<\/code> and see what happens.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"string_handling_in_sram\">5. String handling in SRAM<\/h2>\n\n<p>In the next few example sketches, we will take a closer look at the handling of strings in stack and heap. A few tools are used for this purpose:<\/p>\r\n<ul>\r\n<li>To read the value of a variable at a specific memory address, we use pointers: <code>value = *(datatype*)address = *(datatype*)&amp;variable<\/code>. See my last post on this.<\/li>\r\n<li>We determine the total SRAM still available with <code>getTotalAvailableMemory()<\/code>. The largest contiguous free memory block is returned by <code>getLargestAvailableBlock()<\/code>.\r\n<ul>\r\n<li>The two functions are part of MemoryInfo.Avr.cpp. To make them available, you need to include MemoryInfo.Avr.cpp as an extra tab in the sketches.<\/li>\r\n<li>MemoryInfo.Avr.cpp is written by <a href=\"https:\/\/github.com\/bblanchon\" target=\"_blank\" rel=\"noopener\">Beno\u00eet Blanchon<\/a>. I found the code <a href=\"https:\/\/github.com\/bblanchon\/cpp4arduino\/blob\/master\/HeapFragmentation\/HeapFragmentation.ino\" target=\"_blank\" rel=\"noopener\">here<\/a> on GitHub.<\/li>\r\n<\/ul>\r\n<\/li>\r\n<\/ul>\r\n\n<h3 class=\"wp-block-heading\" id=\"string_analysis_in_stack_and_heap\">5.1. String analysis in stack and heap<\/h3>\n\n<h4 class=\"wp-block-heading\">5.1.1. Example sketch<\/h4>\n\n<p>First, we define only a single string:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_3.ino\" data-enlighter-title=\"example_3.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n    printMemoryDetails();\r\n\r\n    String str = \"Arduino is great\"; \r\n    \r\n    Serial.print(str);\r\n    Serial.println(F(\" - details:\"));\r\n    Serial.print(F(\"Stack address:\\t\"));\r\n    Serial.println((int)&amp;str);\r\n    \r\n    Serial.print(F(\"Heap address: \\t\"));\r\n    int *strPtr; \/\/ pointer to heap\r\n    strPtr = (int*)(int)&amp;str; \r\n    Serial.println(*strPtr);\r\n    \r\n    Serial.print(F(\"Capacity:\\t\"));\r\n    Serial.println(*(uint16_t*)((int)&amp;str + 2));\r\n    \r\n    Serial.print(F(\"Length: \\t\"));\r\n    Serial.println(*(uint16_t*)((int)&amp;str + 4));\r\n    \r\n    Serial.println(F(\"Read from Heap:\"));\r\n    for(unsigned int i=*strPtr; i&lt;(*strPtr + str.length()); i++){\r\n        Serial.print(*(char*)(i));\r\n        Serial.print(\" \");\r\n    }\r\n    Serial.println(\"\\n\");\r\n\r\n    printMemoryDetails();\r\n}\r\n\r\nvoid loop() {\r\n    Serial.println(F(\"In loop: \"));\r\n    printMemoryDetails();\r\n    while(1); \/\/ stop here\r\n}\r\n\r\nvoid printMemoryDetails(){\r\n    Serial.print(F(\"Free memory: \"));\r\n    Serial.print(getTotalAvailableMemory());\r\n    Serial.print(F(\" \/ Biggest free block: \"));\r\n    Serial.println(getLargestAvailableBlock());\r\n    Serial.println();\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_3.ino\" data-enlighter-title=\"MemoryInfo.Avr.cpp\">\/\/ C++ for Arduino\r\n\/\/ What is heap fragmentation?\r\n\/\/ https:\/\/cpp4arduino.com\/\r\n\r\n\/\/ This source file captures the platform dependent code.\r\n\/\/ This version was tested with the AVR Core version 1.6.22\r\n\r\n\/\/ This code is freely inspired from https:\/\/github.com\/McNeight\/MemoryFree\r\n\r\n\/\/ This heap allocator defines this structure to keep track of free blocks.\r\nstruct block_t {\r\n  size_t sz;\r\n  struct block_t *nx;\r\n};\r\n\r\n\/\/ NOTE. The following extern variables are defined in malloc.c in avr-stdlib\r\n\r\n\/\/ A pointer to the first block\r\nextern struct block_t *__flp;\r\n\r\n\/\/ A pointer to the end of the heap, initialized at first malloc()\r\nextern char *__brkval;\r\n\r\n\/\/ A pointer to the beginning of the heap\r\nextern char *__malloc_heap_start;\r\n\r\nstatic size_t getBlockSize(struct block_t *block) {\r\n  return block-&gt;sz + 2;\r\n}\r\n\r\nstatic size_t getUnusedBytes() {\r\n  char foo;\r\n  if (__brkval) {\r\n    return size_t(&amp;foo - __brkval);\r\n  } else {\r\n    return size_t(&amp;foo - __malloc_heap_start);\r\n  }\r\n}\r\n\r\nsize_t getTotalAvailableMemory() {\r\n  size_t sum = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    sum += getBlockSize(block);\r\n  }\r\n  return sum;\r\n}\r\n\r\nsize_t getLargestAvailableBlock() {\r\n  size_t largest = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    size_t size = getBlockSize(block);\r\n    if (size &gt; largest) {\r\n      largest = size;\r\n    }\r\n  }\r\n  return largest;\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n\n<p>This is the output when using an ATmega328P based board:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"389\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3.png\" alt=\"Output example_3.ino (Arduino Nano)\" class=\"wp-image-16900\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3.png 732w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3-300x159.png 300w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_3.ino (Arduino Nano)<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">5.1.2. Review of example_3.ino<\/h4>\n\n<p>The available memory at the beginning of the program is 1815 bytes. Then we define the string &#8220;str&#8221; (= &#8220;Arduino is great&#8221;). It consists of 16 characters and its address in the stack is 2294.&nbsp;<\/p>\r\n<p>&#8220;strPtr&#8221; is the pointer to the address of the string in the heap. With <code>strPtr = (int*)(int)&amp;str;<\/code> we read the pointer from &#8220;str&#8221; (address 2294-2295). We use the same technique to determine the capacity and length. Both values are 16.<\/p>\r\n<p>Then we read the actual string (the content) of the string object directly from the heap. Not that you should do that as a matter of principle! It only serves to prove that the string is actually in the heap.<\/p>\r\n\n<p>The free memory is reduced by 19 bytes by the string. <strong> But why does the string occupy 19 bytes in the heap and not 16?<\/strong> One byte is needed for the null terminator &#8216;\\0&#8217;. And basically, variables in the heap are separated by two more bytes. Honestly speaking, their purpose is not clear to me (I would be grateful for hints!).<\/p>\r\n<p><strong>And where are the 6 bytes for the variable &#8220;str&#8221; from the stack in this calculation?<\/strong> They are not included in the calculation &#8211; the free memory is calculated based on the maximum stack expansion.&nbsp;<\/p>\r\n<p>After the setup is completed, the memory space occupied by the string in the heap is released. Thus, 1815 bytes are available again in loop().<\/p>\r\n\n<h4 class=\"wp-block-heading\">5.1.3. Adaptation for ESP32 and ESP8266<\/h4>\n\n<p>The sketch example_3 works only on AVR boards.&nbsp; Here is an adapted version for the ESP32 and ESP8266:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_3_mod.ino\" data-enlighter-title=\"example_3_mod.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n    printMemoryDetails();\r\n   \r\n    String str = \"Arduino is great\"; \r\n    \r\n    Serial.print(str);\r\n    Serial.println(F(\" - details:\"));\r\n    Serial.print(F(\"Stack address:\\t\"));\r\n    Serial.println((int)&amp;str);\r\n\r\n    Serial.print(F(\"Heap address: \\t\"));\r\n    int *strPtr;\r\n    strPtr = (int*)(int)&amp;str;\r\n    Serial.println(*strPtr);\r\n    \r\n    Serial.print(F(\"Capacity:\\t\"));\r\n    Serial.println(*(uint16_t*)((int)&amp;str + 4));\r\n    \r\n    Serial.print(F(\"Length:   \\t\"));\r\n    Serial.println(*(uint16_t*)((int)&amp;str + 8));\r\n    \r\n    Serial.println(F(\"Read from Heap:\"));\r\n    for(unsigned int i=*strPtr; i&lt;(*strPtr + str.length()); i++){\r\n        Serial.print(*(char*)(i));\r\n        Serial.print(\" \");\r\n    }\r\n    Serial.println(\"\\n\");\r\n    \r\n    printMemoryDetails();\r\n}\r\n\r\nvoid loop() {\r\n   Serial.println(F(\"In loop: \"));\r\n    printMemoryDetails();\r\n    while(1){   \/\/ stop here\r\n        delay(1000); \/\/ prevents WDT reset on ESP8266\r\n    }\r\n}\r\n\r\nvoid printMemoryDetails(){\r\n    Serial.print(F(\"Free memory: \"));\r\n    \/\/ for ESP32:\r\n    Serial.println(esp_get_free_heap_size());\r\n    \/\/ for ESP8266:\r\n    \/\/Serial.println(ESP.getFreeHeap());  \r\n    Serial.println();\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>The sketch generates the following output when using an ESP32:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3__esp32.png\"><img loading=\"lazy\" decoding=\"async\" width=\"753\" height=\"392\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3__esp32.png\" alt=\"Output example_3_mod.ino (ESP32)\" class=\"wp-image-17006\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3__esp32.png 753w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_3__esp32-300x156.png 300w\" sizes=\"auto, (max-width: 753px) 100vw, 753px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_3_mod.ino (ESP32)<\/figcaption><\/figure>\n\n<p>Strings are handled differently on the ESP32. If you play a little with the length of the string, you will see:<\/p>\r\n<ul>\r\n<li>If the string consists of up to 15 characters, a capacity of 15 characters (= 15 bytes) is reserved for it. As with the AVR microcontrollers, three bytes are added so that the space required for the character string in the heap is 18 bytes. In addition, you find 12 bytes occupied for the &#8220;string variable&#8221; in the stack.<\/li>\r\n<li>If the length is between 15 and 31 characters, then 31 characters are reserved, between 32 and 47 it is 47 &#8211; and so it goes on in steps of 16.<\/li>\r\n<li>Strings with a length of less than 10 are not saved on the heap at all. Try it by shortening the string to &#8220;Arduino&#8221;. The sketch then outputs a capacity of 28265 and a length of 111. That&#8217;s nonsense, of course. What we read here is 28265 = 0x6E69 \u21d2 110 (0x6E) \/ 105 (0x69) \u21d2 ASCII characters &#8216;n&#8217; \/ &#8216;i&#8217; and 111 \u21d2 &#8216;o&#8217;, i.e. the characters from &#8220;Arduino&#8221;.\r\n<ul>\r\n<li>This is called Small String Optimization (SSO).<\/li>\r\n<\/ul>\r\n<\/li>\r\n<\/ul>\r\n<p>The ESP8266 does not save strings that consist of less than 11 characters; otherwise it behaves similarly.<\/p>\r\n\n<p>For the next examples, I won&#8217;t make any adjustments for non-AVR boards, as this post is already way too long. Based on the previous explanations, you should be able to do this yourself if needed.<\/p>\r\n\n<h3 class=\"wp-block-heading\" id=\"heap_fragmentation\">5.2. Heap fragmentation <\/h3>\n\n<h4 class=\"wp-block-heading\">5.2.1. Example sketch<\/h4>\n\n<p>Many people warn against the use of strings in the field of microcontrollers. One of the main arguments is potential heap fragmentation (remember the bookshelf mentioned at the beginning?).<\/p>\r\n<p>With the following sketch, we create a hole in the heap:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_4.ino\" data-enlighter-title=\"example_4.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n    Serial.print(F(\"Free memory: \"));\r\n    Serial.print(getTotalAvailableMemory());\r\n    Serial.print(F(\" \/ Biggest free block: \"));\r\n    Serial.println(getLargestAvailableBlock());\r\n    Serial.println();\r\n    \r\n    String s = \"Arduino is great\"; \r\n    \/\/s.reserve(26);\r\n    printStringDetails(s);\r\n        \r\n    String t = \"ESP32 is fast\";  \r\n    \/\/t.reserve(23);\r\n    printStringDetails(t); \r\n        \r\n    String u = \"Wemos is fabulous\"; \r\n    \/\/u.reserve(27);\r\n    printStringDetails(u); \r\n    \r\n   \r\n    Serial.println();\r\n    for(int i = 1; i&lt;=10; i++){\r\n        s += \"!\";\r\n    }\r\n    printStringDetails(s); \r\n    \r\n    for(int i = 1; i&lt;=10; i++){\r\n        t += \"!\";\r\n    }\r\n    printStringDetails(t); \r\n   \r\n    for(int i = 1; i&lt;=10; i++){\r\n        u += \"!\";\r\n    }\r\n    printStringDetails(u); \r\n}\r\n\r\nvoid loop() {}\r\n\r\nvoid printStringDetails(String &amp;str){\r\n    Serial.print(str);\r\n    Serial.println(F(\" - details:\"));\r\n    Serial.print(F(\"Stack address: \"));\r\n    Serial.print((int)&amp;str);\r\n    Serial.print(F(\" \/ Heap address: \"));\r\n    \r\n    int *strPtr; \/\/Pointer to heap address\r\n    uint16_t capacity = *(uint16_t*)((int)&amp;str + 2); \/\/ for some boards + 4\r\n    uint16_t len = *(uint16_t*)((int)&amp;str + 4); \/\/ for some boards + 6\r\n    strPtr = (int*)(int)&amp;str;\r\n    \r\n    Serial.print(*strPtr);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println(*strPtr + capacity + 2);\r\n    Serial.print(F(\"Capacity: \"));\r\n    Serial.print(capacity);\r\n    Serial.print(F(\" \/ Length: \"));\r\n    Serial.println(len);\r\n    \r\n\/\/    Read from Heap if you want\r\n\/\/    for(unsigned int i=*strPtr; i&lt;(*strPtr + str.length()); i++){\r\n\/\/        Serial.print(*(char*)(i));\r\n\/\/        Serial.print(\" \");\r\n\/\/    }\r\n\/\/    Serial.println();\r\n    \r\n    \/\/ comment the following lines if you use a non-AVR based board\r\n    Serial.print(F(\"Free memory: \"));\r\n    Serial.print(getTotalAvailableMemory());\r\n    Serial.print(F(\" \/ Biggest free block: \"));\r\n    Serial.println(getLargestAvailableBlock());\r\n    Serial.println(\"\");\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_4.ino\" data-enlighter-title=\"MemoryInfo.Avr.cpp\">\/\/ C++ for Arduino\r\n\/\/ What is heap fragmentation?\r\n\/\/ https:\/\/cpp4arduino.com\/\r\n\r\n\/\/ This source file captures the platform dependent code.\r\n\/\/ This version was tested with the AVR Core version 1.6.22\r\n\r\n\/\/ This code is freely inspired from https:\/\/github.com\/McNeight\/MemoryFree\r\n\r\n\/\/ This heap allocator defines this structure to keep track of free blocks.\r\nstruct block_t {\r\n  size_t sz;\r\n  struct block_t *nx;\r\n};\r\n\r\n\/\/ NOTE. The following extern variables are defined in malloc.c in avr-stdlib\r\n\r\n\/\/ A pointer to the first block\r\nextern struct block_t *__flp;\r\n\r\n\/\/ A pointer to the end of the heap, initialized at first malloc()\r\nextern char *__brkval;\r\n\r\n\/\/ A pointer to the beginning of the heap\r\nextern char *__malloc_heap_start;\r\n\r\nstatic size_t getBlockSize(struct block_t *block) {\r\n  return block-&gt;sz + 2;\r\n}\r\n\r\nstatic size_t getUnusedBytes() {\r\n  char foo;\r\n  if (__brkval) {\r\n    return size_t(&amp;foo - __brkval);\r\n  } else {\r\n    return size_t(&amp;foo - __malloc_heap_start);\r\n  }\r\n}\r\n\r\nsize_t getTotalAvailableMemory() {\r\n  size_t sum = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    sum += getBlockSize(block);\r\n  }\r\n  return sum;\r\n}\r\n\r\nsize_t getLargestAvailableBlock() {\r\n  size_t largest = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    size_t size = getBlockSize(block);\r\n    if (size &gt; largest) {\r\n      largest = size;\r\n    }\r\n  }\r\n  return largest;\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n\n<p>On an Arduino Nano I got the following output:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"860\" height=\"742\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_4.png\" alt=\"Output example_4.ino (Arduino Nano)\" class=\"wp-image-16923\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_4.png 860w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_4-300x259.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output__example_4-768x663.png 768w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_4.ino (Arduino Nano)<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">5.2.2. Review of example_4<\/h4>\n\n<p>We create three strings:<\/p>\r\n<ol>\r\n<li>s: &#8220;Arduino is great&#8221; &#8211; 16 characters, requires 19 bytes in the heap.<\/li>\r\n<li>t:&nbsp; &#8220;ESP32 is fast&#8221; -13 characters, requires 16 bytes in the heap.<\/li>\r\n<li>u: &#8220;Wemos is fabulous&#8221; &#8211; 17 characters, requires 20 bytes in the heap.<\/li>\r\n<\/ol>\r\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-1024x468.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"468\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-1024x468.png\" alt=\"Heap fragmentation\" class=\"wp-image-17135\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-1024x468.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-300x137.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-768x351.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation-1320x604.png 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2023\/01\/heap__fragmentation.png 1329w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Heap fragmentation<\/figcaption><\/figure>\n\n<p>All three strings are stored one after the other in the heap (order: s\u2192t\u2192u). Then we extend string &#8220;s&#8221; by 10 exclamation marks. As a result, it takes up an additional 10 bytes and no longer fits in its original memory location. Therefore, it moves to the next free memory space in the heap. The heap now has a hole of 19 bytes, and the order is t\u2192u\u2192s.<\/p>\r\n<p>Now, we extend string &#8220;t&#8221; by 10 exclamation marks. Its start address moves to the former start address of &#8220;S&#8221;. Despite the extension, however, there is still a gap of 9 bytes (532 &#8211; 540).&nbsp;<\/p>\r\n<p>Finally, &#8220;u&#8221; also gets its 10 extra characters. There is a 29 byte gap between 532 and 560. &#8220;u&#8221;, however, needs 30 bytes and therefore moves up (sequence t\u2192s\u2192u) and the gap becomes larger again.<\/p>\r\n<p>In this example, the gap is not a big problem because the heap is &#8220;clean&#8221; again when you exit the setup. More problematic is the handling of strings in loop(). If you work with strings of different lengths, the holes can add up if things go wrong. A great article taking this to the extreme can be found <a href=\"https:\/\/cpp4arduino.com\/2018\/11\/06\/what-is-heap-fragmentation.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\r\n\n<h4 class=\"wp-block-heading\">5.2.3. Prevent heap fragmentation with reserve()<\/h4>\n\n<p>The fragmentation just shown can be easily prevented. You just have to think about how long your string could be at maximum and reserve the space with <code>Stringname.reserve(maximum_length)<\/code>. Try it by uncommenting lines 11, 15 and 19 in example_4.<\/p>\r\n<p>Even if you reserve a bit more memory than necessary (e.g. because you don&#8217;t know the actual maximum length), you may lose less memory than by fragmentation. Moreover, you have things under control. And you save time, since moving the strings in the heap requires a significant amount of computation.&nbsp;<\/p>\r\n\n<h3 class=\"wp-block-heading\" id=\"string_concatenation\">5.3. Concatenating strings<\/h3>\n\n<h4 class=\"wp-block-heading\">5.3.1 Example sketch<\/h4>\n\n<p>But there is at least one more pitfall when using strings, and that concerns their concatenation.<\/p>\r\n<p>In the following sketch, we concatenate (add) three strings:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_5.ino\" data-enlighter-title=\"example_5.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000);\r\n    \r\n    String s = \"Arduino is great\";\r\n    printStringDetails(s); \r\n    String t = \"ESP32 is fast\";\r\n    printStringDetails(t); \r\n    String u = \"Wemos is fabulous\";\r\n    printStringDetails(u); \r\n    \r\n    String v = \"\";\r\n    v = s + t + u; \r\n\/\/    v += s;  \/\/ alternative: v.concat(s);\r\n\/\/    v += t;  \/\/ alternative: v.concat(t);\r\n\/\/    v += u;  \/\/ alternative: v.concat(u);\r\n    printStringDetails(v);\r\n}\r\n\r\nvoid loop() {}\r\n\r\nvoid printStringDetails(String &amp;str){\r\n    Serial.print(str);\r\n    Serial.println(F(\" - details:\"));\r\n    Serial.print(F(\"Stack address: \"));\r\n    Serial.print((int)&amp;str);\r\n    Serial.print(F(\" \/ Heap address: \"));\r\n    \r\n    int *strPtr; \/\/Pointer to heap address\r\n    uint16_t capacity = *(uint16_t*)((int)&amp;str + 2);\r\n    uint16_t len = *(uint16_t*)((int)&amp;str + 4);\r\n    strPtr = (int*)(int)&amp;str;\r\n    \r\n    Serial.print(*strPtr);\r\n    Serial.print(F(\" - \"));\r\n    Serial.println(*strPtr + capacity + 2);\r\n    Serial.print(F(\"Capacity: \"));\r\n    Serial.print(capacity);\r\n    Serial.print(F(\" \/ Length: \"));\r\n    Serial.println(len);\r\n    \r\n\/\/    for(uint16_t i=*strPtr; i&lt;(*strPtr + str.length()); i++){\r\n\/\/        Serial.print(*(char*)(i));\r\n\/\/        Serial.print(\" \");\r\n\/\/    }\r\n\/\/    Serial.println();\r\n    Serial.print(F(\"Free memory: \"));\r\n    Serial.print(getTotalAvailableMemory());\r\n    Serial.print(F(\" \/ Biggest free block: \"));\r\n    Serial.println(getLargestAvailableBlock());\r\n    Serial.println(\"\");\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_5.ino\" data-enlighter-title=\"MemoryInfo.Avr.cpp\">\/\/ C++ for Arduino\r\n\/\/ What is heap fragmentation?\r\n\/\/ https:\/\/cpp4arduino.com\/\r\n\r\n\/\/ This source file captures the platform dependent code.\r\n\/\/ This version was tested with the AVR Core version 1.6.22\r\n\r\n\/\/ This code is freely inspired from https:\/\/github.com\/McNeight\/MemoryFree\r\n\r\n\/\/ This heap allocator defines this structure to keep track of free blocks.\r\nstruct block_t {\r\n  size_t sz;\r\n  struct block_t *nx;\r\n};\r\n\r\n\/\/ NOTE. The following extern variables are defined in malloc.c in avr-stdlib\r\n\r\n\/\/ A pointer to the first block\r\nextern struct block_t *__flp;\r\n\r\n\/\/ A pointer to the end of the heap, initialized at first malloc()\r\nextern char *__brkval;\r\n\r\n\/\/ A pointer to the beginning of the heap\r\nextern char *__malloc_heap_start;\r\n\r\nstatic size_t getBlockSize(struct block_t *block) {\r\n  return block-&gt;sz + 2;\r\n}\r\n\r\nstatic size_t getUnusedBytes() {\r\n  char foo;\r\n  if (__brkval) {\r\n    return size_t(&amp;foo - __brkval);\r\n  } else {\r\n    return size_t(&amp;foo - __malloc_heap_start);\r\n  }\r\n}\r\n\r\nsize_t getTotalAvailableMemory() {\r\n  size_t sum = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    sum += getBlockSize(block);\r\n  }\r\n  return sum;\r\n}\r\n\r\nsize_t getLargestAvailableBlock() {\r\n  size_t largest = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    size_t size = getBlockSize(block);\r\n    if (size &gt; largest) {\r\n      largest = size;\r\n    }\r\n  }\r\n  return largest;\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n\n<p>Output on an Arduino Nano:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"860\" height=\"490\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_5.png\" alt=\"Output example_5.ino (Arduino Nano)\" class=\"wp-image-16929\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_5.png 860w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_5-300x171.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example_5-768x438.png 768w\" sizes=\"auto, (max-width: 860px) 100vw, 860px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_5.ino (Arduino Nano)<\/figcaption><\/figure>\n\n<h4 class=\"wp-block-heading\">5.3.2. Review of example_5<\/h4>\n\n<p>The sketch tears a big hole of 53 bytes in the heap. The reason for this is the intermediate result that is stored in the heap. s and t and u are added first, and then the result is assigned to v.<\/p>\r\n<p>The good news is that you can prevent the hole by making a tiny change in the code. Comment line 13 and uncomments lines 14 to 16. The result is &#8220;hole-free&#8221;. &#8220;Free memory&#8221; and &#8220;Biggest free block&#8221; are 1659 bytes. Just try it out.<\/p>\r\n\n<h3 class=\"wp-block-heading\" id=\"should_i_use_strings\">5.4. So, should I use strings or not?<\/h3>\n\n<p>For many programmers, strings are a witches&#8217; brew in the microcontroller area, an absloute no-go! No question: Character arrays are more resource-efficient and faster. However, when using them, you can also make a lot of mistakes. In addition, the code is harder to read, at least for beginners. In addition, many hobbyists today turn to fast microcontrollers equipped with plenty of SRAM, such as the ESP32 or ESP8266.<\/p>\r\n<p>If you want to be confirmed that you should not use strings, you can read this article: <a href=\"https:\/\/majenko.co.uk\/blog\/our-blog-1\/the-evils-of-arduino-strings-32\" target=\"_blank\" rel=\"noopener\">The evils of Arduino Strings<\/a>. If you wish to hear a more nuanced verdict, check out the wonderful article <a href=\"https:\/\/www.forward.com.au\/pfod\/ArduinoProgramming\/ArduinoStrings\/index.html\" target=\"_blank\" rel=\"noopener\">Taming Arduino Strings<\/a>.<\/p>\r\n<p>My opinion is: if speed is not critical, and you are not short of SRAM, then go ahead and use strings. I certainly do! But be aware of the dangers and take some precautions:<\/p>\r\n<ul>\r\n<li>Avoids creating strings in loop().<\/li>\r\n<li>Use reserve() if the length of your strings can change.<\/li>\r\n<li>Concatenate strings using &#8220;+=&#8221; or concat().<\/li>\r\n<li>To save SRAM, pass strings as references (see last post).<\/li>\r\n<\/ul>\r\n<p>You can find more tips <a href=\"https:\/\/www.forward.com.au\/pfod\/ArduinoProgramming\/ArduinoStrings\/index.html#controlMem\" target=\"_blank\" rel=\"noopener\">here<\/a> in the already mentioned article &#8220;Taming Arduino Strings&#8221; or in <a href=\"https:\/\/cpp4arduino.com\/2018\/11\/21\/eight-tips-to-use-the-string-class-efficiently.html\" target=\"_blank\" rel=\"noopener\">this nice article<\/a>.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"character_arrays\">6. Character arrays<\/h2>\n\n<p>For the sake of completeness, a few words about character arrays. If you don&#8217;t specify the length, they will occupy as many bytes in the stack as they have characters, plus one for the null terminator, as already mentioned. If you do not want to change the character array during runtime, then you should declare it as a constant. This protects you from your own mistakes and makes the code clearer. If the length of the character array varies, then reserve as much space as you expect as a maximum.<\/p>\r\n<p>Here is the example of this:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_6.ino\" data-enlighter-title=\"example_6.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    const char a[] = \"I am a character array\";\r\n    char b[30] = \"Arduino is great\"; \r\n    char c[30] = \"ESP32 is fast\";  \r\n    char d[30] = \"Wemos is fabulous\"; \r\n\r\n    printCharArrayDetails(a, sizeof(a)); \r\n    printCharArrayDetails(b, sizeof(b)); \r\n    printCharArrayDetails(c, sizeof(c)); \r\n    printCharArrayDetails(d, sizeof(d));    \r\n    Serial.println();\r\n    \r\n    strcat(b, \"!!!!!!!!!!\");\r\n    strcat(c, \"!!!!!!!!!!\");\r\n    strcat(d, \"!!!!!!!!!!\");\r\n    \r\n    printCharArrayDetails(b, sizeof(b)); \r\n    printCharArrayDetails(c, sizeof(c)); \r\n    printCharArrayDetails(d, sizeof(d));      \r\n}\r\n\r\nvoid loop() {}\r\n\r\nvoid printCharArrayDetails(char* cArr, int len){\r\n    for(int i=0; i&lt;len; i++){\r\n        Serial.print(cArr[i]);\r\n    }\r\n    Serial.println(F(\" - details:\"));\r\n    Serial.print(F(\"Length: \"));\r\n    Serial.print(len);\r\n    Serial.print(F(\" \/ Address: \"));\r\n    Serial.print((int)cArr);\r\n    Serial.println(\"\\n\\r\");\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>And here is the output when using an Arduino Nano:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__6.png\"><img loading=\"lazy\" decoding=\"async\" width=\"885\" height=\"525\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__6.png\" alt=\"Output example_6.ino (Arduino Nano)\" class=\"wp-image-17031\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__6.png 885w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__6-300x178.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__6-768x456.png 768w\" sizes=\"auto, (max-width: 885px) 100vw, 885px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_6.ino (Arduino Nano)<\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\" id=\"move_variables_to_heap\">7. Force variables into the heap<\/h2>\n\n<p>As you have seen, most local variables are automatically stored in the stack, unless they are strings. But you can also force variables into the heap. There are two methods for this:<\/p>\r\n<ol>\r\n<li>Declaration with the keyword <code>new<\/code>.<\/li>\r\n<li>Allocation of memory space per <code>malloc()<\/code>.<\/li>\r\n<\/ol>\r\n<p>The following sketch illustrates their use:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_7.ino\" data-enlighter-title=\"example_7.ino\">void setup() {\r\n    Serial.begin(9600);\r\n    delay(2000);\r\n\r\n    int *a = new int[5];  \/\/ reserve memory for 5 integers \r\n    for(int i=0; i&lt;5; i++){\r\n        a[i] = 2*i;\r\n    }\r\n    int heapAddrA = *(int*)(int)&amp;a; \/\/ just to show you find a in heap\r\n    \r\n    char *b = new char[2]; \/\/ reserve memory for a char array\r\n    b[0] = 'b';\r\n    int heapAddrB = *(int*)(int)&amp;b;\r\n\r\n    Serial.print(F(\"Stack address a: \"));\r\n    Serial.println((int)&amp;a);\r\n    Serial.print(F(\"Stack address b: \"));\r\n    Serial.println((int)&amp;b);\r\n    \r\n    Serial.print(F(\"Heap address a:  \"));\r\n    Serial.println(heapAddrA);\r\n    Serial.print(F(\"Heap address b:  \"));\r\n    Serial.println(heapAddrB);\r\n    \r\n    int *c = (int*)malloc(5 * sizeof(int)); \/\/ reserve memory for 5 integers\r\n    for(int i=0; i&lt;5; i++){  \r\n        c[i] = i * 2000;\r\n    }\r\n\r\n    int heapAddrC = *(int*)(int)&amp;c;\r\n        \r\n    Serial.print(F(\"Stack address c: \"));\r\n    Serial.println((int)&amp;c);\r\n    \r\n    Serial.print(F(\"Heap address c:  \"));\r\n    Serial.println(heapAddrC);\r\n    Serial.println();   \r\n    \r\n    Serial.print(F(\"Available memory before deletion: \\t\"));\r\n    Serial.println(getTotalAvailableMemory()); \r\n    delete a;  \/\/ new -&gt; delete\r\n    delete b;\r\n    free(c);    \/\/ malloc -&gt; free\r\n    Serial.print(F(\"New available memory after deletion: \\t\"));\r\n    Serial.println(getTotalAvailableMemory()); \r\n}\r\n\r\nvoid loop() {}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_7.ino\" data-enlighter-title=\"MemoryInfo.Avr.cpp\">\/\/ C++ for Arduino\r\n\/\/ What is heap fragmentation?\r\n\/\/ https:\/\/cpp4arduino.com\/\r\n\r\n\/\/ This source file captures the platform dependent code.\r\n\/\/ This version was tested with the AVR Core version 1.6.22\r\n\r\n\/\/ This code is freely inspired from https:\/\/github.com\/McNeight\/MemoryFree\r\n\r\n\/\/ This heap allocator defines this structure to keep track of free blocks.\r\nstruct block_t {\r\n  size_t sz;\r\n  struct block_t *nx;\r\n};\r\n\r\n\/\/ NOTE. The following extern variables are defined in malloc.c in avr-stdlib\r\n\r\n\/\/ A pointer to the first block\r\nextern struct block_t *__flp;\r\n\r\n\/\/ A pointer to the end of the heap, initialized at first malloc()\r\nextern char *__brkval;\r\n\r\n\/\/ A pointer to the beginning of the heap\r\nextern char *__malloc_heap_start;\r\n\r\nstatic size_t getBlockSize(struct block_t *block) {\r\n  return block-&gt;sz + 2;\r\n}\r\n\r\nstatic size_t getUnusedBytes() {\r\n  char foo;\r\n  if (__brkval) {\r\n    return size_t(&amp;foo - __brkval);\r\n  } else {\r\n    return size_t(&amp;foo - __malloc_heap_start);\r\n  }\r\n}\r\n\r\nsize_t getTotalAvailableMemory() {\r\n  size_t sum = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    sum += getBlockSize(block);\r\n  }\r\n  return sum;\r\n}\r\n\r\nsize_t getLargestAvailableBlock() {\r\n  size_t largest = getUnusedBytes();\r\n  for (struct block_t *block = __flp; block; block = block-&gt;nx) {\r\n    size_t size = getBlockSize(block);\r\n    if (size &gt; largest) {\r\n      largest = size;\r\n    }\r\n  }\r\n  return largest;\r\n}<\/pre>\r\n<p>&nbsp;<\/p>\r\n\n<p>Here is the output:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__7.png\"><img loading=\"lazy\" decoding=\"async\" width=\"740\" height=\"250\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__7.png\" alt=\"Output example_7 (Arduino Nano)\" class=\"wp-image-17036\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__7.png 740w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/output_example__7-300x101.png 300w\" sizes=\"auto, (max-width: 740px) 100vw, 740px\" \/><\/a><figcaption class=\"wp-element-caption\">Output example_7 (Arduino Nano)<\/figcaption><\/figure>\n\n<p>You can see that the objects created with <code>new<\/code> and <code>malloc()<\/code> each occupy two bytes in the stack. However, this is only the pointer to the actual data in the heap.&nbsp;<\/p>\r\n\n<p><strong>But why should I do that? <\/strong>There are applications where you need to create variables or objects during runtime, but you don&#8217;t know before their size and how many you will need. Then <code>new<\/code> and <code>malloc()<\/code> are ideal for reserving the required storage space. The advantage is that you can release the storage space with <code>delete<\/code> or <code>free()<\/code>. At first glance, <code>new<\/code> and <code>malloc()<\/code> do the same thing, but there are a few important differences. Interested parties may look <a href=\"https:\/\/www.geeksforgeeks.org\/new-vs-malloc-and-free-vs-delete-in-c\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\r\n<p>The use of <code>new<\/code> and <code>malloc()<\/code> is not free of risks. If you forget to free the memory again, you could run out of memory. Or you forget that you have already freed the space and still try to access it with your pointer. The problem is: the pointer still works! For example, inserts <code>Serial.println(c[3])<\/code> after <code>free(c)<\/code>. You are still reading the value that was there before. However, only as long as the memory space has not yet been overwritten. After that, you read just &#8220;something&#8221; there and wonder why your program behaves strangely. Such bugs are difficult to find.<\/p>\r\n\n<h2 class=\"wp-block-heading\" id=\"save_progmem\">8. Saving SRAM with PROGMEM and F()<\/h2>\n\n<h3 class=\"wp-block-heading\">8.1. PROGMEM<\/h3>\n\n<p>Constants that consume too much SRAM can be conveniently banished from the SRAM. They are then read from the flash. This is particularly useful for long arrays and strings. When defining the constants, you just need to add the keyword PROGMEM, i.e.: <code>const datatype arrayName[] PROGMEM = { data };<\/code>.<\/p>\r\n<p>Reading the data requires only a little getting used to. Instead of <code>element_i = arrayName[i];<\/code> you write <code>element_i = pgm_read_type_near (arrayName + i)<\/code> with <code>type = byte, word, oder dword<\/code>.<\/p>\r\n<p>Here is an example sketch to illustrate the function:<\/p>\r\n\n<div class=\"scroll-paragraph\">\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"example_8.ino\" data-enlighter-title=\"example_8.ino\">const byte byteArray[] PROGMEM = {11, 22, 33, 44, 55, 66};\r\nconst int intArray[] PROGMEM = {1111, 2222, 3333, 4444};\r\nconst unsigned long longArray[] PROGMEM = {1111111, 2222222, 3333333, 4444444, 5555555};\r\nconst char charArray[] PROGMEM = {\"Hello, PROGMEM helps you saving SRAM!\"};\r\n\r\nvoid setup() {\r\n    Serial.begin(9600);\r\n    delay(2000); \/\/ needed for some boards\r\n\r\n    for(unsigned int i=0; i&lt;sizeof(byteArray)\/sizeof(byte); i++){\r\n        byte element = pgm_read_byte_near(byteArray + i);\r\n        Serial.print(element); Serial.print(\" \");\r\n    }\r\n    Serial.println(\"\\n\");\r\n\r\n    for(unsigned int i=0; i&lt;sizeof(intArray)\/sizeof(int); i++){\r\n        int element = pgm_read_word_near(intArray + i);\r\n        Serial.print(element); Serial.print(\" \");\r\n    }\r\n    Serial.println(\"\\n\");\r\n\r\n    for(unsigned int i=0; i&lt;sizeof(longArray)\/sizeof(long); i++){\r\n        long element = pgm_read_dword_near(longArray + i);\r\n        Serial.print(element); Serial.print(\" \");\r\n    }\r\n    Serial.println(\"\\n\");\r\n\r\n    for(unsigned int i=0; i&lt;strlen_P(charArray); i++){  \/\/ alternative: i&lt;sizeof(charArray)\/sizeof(char);\r\n        char element = pgm_read_byte_near(charArray + i);\r\n        Serial.print(element);\r\n    }\r\n    Serial.println(\"\\n\");    \r\n}\r\n\r\nvoid loop() {}<\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n\n<p>I wrote a second version of example_8 without PROGMEM (but not shown here) and then uploaded both versions for comparison. The difference in the allocation of the SRAM by global variables is 72 bytes:<\/p>\r\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/with_vs_without_progmem.png\"><img loading=\"lazy\" decoding=\"async\" width=\"957\" height=\"264\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/with_vs_without_progmem.png\" alt=\"Saving SRAM using PROGMEM\" class=\"wp-image-17044\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/with_vs_without_progmem.png 957w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/with_vs_without_progmem-300x83.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/with_vs_without_progmem-768x212.png 768w\" sizes=\"auto, (max-width: 957px) 100vw, 957px\" \/><\/a><figcaption class=\"wp-element-caption\">Saving SRAM using PROGMEM<\/figcaption><\/figure>\n\n<p>This is precisely the 72 bytes needed by the constants in example_8 on an ATmega328P based board. If you are recounting, please keep in mind the zero terminator.<\/p>\r\n\n<h3 class=\"wp-block-heading\">8.2. The F() macro<\/h3>\n\n<p>You may have noticed that I consistently use the F macro in this post, i.e. <code>Serial.print(F(\"blabla\"));<\/code>. Without F() &#8220;blabla&#8221; would be written into the static data area of the SRAM at program start and read from there when needed. With F() the microcontroller reads &#8220;blabla&#8221; directly from the flash. This is a simple way to save SRAM. I do not have an example sketch for this. Just take out an F() once in the above sketches and compare the space consumed by global variables<\/p>\r\n\n<h2 class=\"wp-block-heading\">Acknowledgement<\/h2>\n\n<p>I owe the background of my post image to <a href=\"https:\/\/pixabay.com\/users\/lenaertsdaan-535541\/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1128227\" target=\"_blank\" rel=\"noopener\">Daan Lenaerts<\/a> on <a href=\"https:\/\/pixabay.com\/\/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1128227\" target=\"_blank\" rel=\"noopener\">Pixabay<\/a>.<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>This post is a journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings? Here you will find the answers. <\/p>\n","protected":false},"author":1,"featured_media":17049,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[543],"tags":[556,2016,1725,2010,2009,2007,2013,2012,2017,2011,2006,2008,2015,2014,1729],"class_list":["post-17307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-boards-and-microcontrollers","tag-arduino-en-2","tag-dynamic","tag-eeprom-en","tag-f-en","tag-flash-en","tag-heap-en","tag-heap-fragmentation","tag-malloc-en","tag-memory-en","tag-progmem-en","tag-sram-en","tag-stack-en","tag-static","tag-static-data-en","tag-strings-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>SRAM Management &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/sram-management\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SRAM Management &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/sram-management\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-03T20:30:25+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-11-27T08:37:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"1000\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"32 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"SRAM Management\",\"datePublished\":\"2023-02-03T20:30:25+00:00\",\"dateModified\":\"2024-11-27T08:37:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management\"},\"wordCount\":3898,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/post_image.jpg\",\"keywords\":[\"Arduino\",\"dynamic\",\"EEPROM\",\"F()\",\"flash\",\"heap\",\"heap fragmentation\",\"malloc\",\"memory\",\"progmem\",\"SRAM\",\"stack\",\"static\",\"static data\",\"Strings\"],\"articleSection\":[\"Boards and Microcontrollers\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management\",\"name\":\"SRAM Management &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/post_image.jpg\",\"datePublished\":\"2023-02-03T20:30:25+00:00\",\"dateModified\":\"2024-11-27T08:37:15+00:00\",\"description\":\"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/post_image.jpg\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2022\\\/12\\\/post_image.jpg\",\"width\":1000,\"height\":1000},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/sram-management#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SRAM Management\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"SRAM Management &#8226; Wolles Elektronikkiste","description":"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management","og_locale":"en_US","og_type":"article","og_title":"SRAM Management &#8226; Wolles Elektronikkiste","og_description":"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management","og_site_name":"Wolles Elektronikkiste","article_published_time":"2023-02-03T20:30:25+00:00","article_modified_time":"2024-11-27T08:37:15+00:00","og_image":[{"width":1000,"height":1000,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg","type":"image\/jpeg"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"32 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"SRAM Management","datePublished":"2023-02-03T20:30:25+00:00","dateModified":"2024-11-27T08:37:15+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management"},"wordCount":3898,"commentCount":0,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg","keywords":["Arduino","dynamic","EEPROM","F()","flash","heap","heap fragmentation","malloc","memory","progmem","SRAM","stack","static","static data","Strings"],"articleSection":["Boards and Microcontrollers"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/sram-management#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management","url":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management","name":"SRAM Management &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg","datePublished":"2023-02-03T20:30:25+00:00","dateModified":"2024-11-27T08:37:15+00:00","description":"A journey into the depths of SRAM, Heap and Stack. How are variables stored there? What should be considered when using strings?","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/sram-management"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2022\/12\/post_image.jpg","width":1000,"height":1000},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/sram-management#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"SRAM Management"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/17307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=17307"}],"version-history":[{"count":2,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/17307\/revisions"}],"predecessor-version":[{"id":22859,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/17307\/revisions\/22859"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/17049"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=17307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=17307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=17307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}