// Free memory at the end of this sketch from //https://github.com/McNeight/MemoryFree // slight mods by Matthew Ford // from https://forum.arduino.cc/index.php?topic=650120.0 @RayLivingston // MemoryFree library based on code posted here: // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213583720/15 // Extended by Matthew Murdoch to include walking of the free list. // Further extended by Ray Livingston for additinal output options #ifndef MEMORY_FREE_H #define MEMORY_FREE_H #include #include #ifdef __cplusplus extern "C" { #endif #define SHOW_SIZES showSizes( F( __FILE__ ), __LINE__ ); #define SET_MARK setMark( F( __FILE__ ), __LINE__ ); #define SHOW_MARK showMark( F( __FILE__ ), __LINE__ ); void initFreeMemory(); int freeMemory(); void showMemory(const char *s); void showMemory_P(const __FlashStringHelper *s); void showSizes(const __FlashStringHelper *s, int line); void setMark(const __FlashStringHelper *s, int line); void showMark(const __FlashStringHelper *s, int line); int freeListSize(); #ifdef __cplusplus } #endif #endif #if (ARDUINO >= 100) #include #else #include #endif extern unsigned int __heap_start; extern void *__brkval; /* * The free list structure as maintained by the * avr-libc memory allocation routines. */ struct __freelist { size_t sz; struct __freelist *nx; }; /* The head of the free list structure */ extern struct __freelist *__flp; //#include "MemoryFree.h" static unsigned int max_ram = 0; static unsigned int stack_top = 0; static unsigned int stack_bottom = 0; static unsigned int stack_size = 0; static unsigned int heap_start = 0; static unsigned int heap_end = 0; static unsigned int heap_size = 0; static unsigned int free_size = 0; static unsigned int mark_stack = 0; static unsigned int mark_heap = 0; struct __freelist* current; int total = 0; void initFreeMemory() { char *__stack = 0; max_ram = RAMEND - RAMSTART + 1; stack_top = max_ram; stack_bottom = ((unsigned int)&__stack - RAMSTART) + 1; stack_size = stack_top - stack_bottom; mark_stack = stack_size; heap_start = (unsigned int)__malloc_heap_start - RAMSTART; void *__heap = malloc(1); heap_end = (unsigned int)__heap - RAMSTART; heap_end -= 2; free(__heap); heap_size = heap_end - heap_start; mark_heap = heap_size; free_size = (unsigned int)stack_top - (unsigned int)heap_end + freeListSize(); Serial.print("bss_size = "); Serial.println(heap_start); Serial.print("\nstack_top = "); Serial.println(stack_top); Serial.print("stack_bottom = "); Serial.println(stack_bottom); Serial.print("stack_size = "); Serial.println(stack_size); Serial.print("\nheap start = "); Serial.println(heap_start); Serial.print("heap end = "); Serial.println(heap_end); Serial.print("heap size = "); Serial.println(heap_size); Serial.print("\nfree_size = "); Serial.println(free_size); Serial.print("used_size = "); Serial.println(max_ram - free_size); Serial.print("\n"); } void setMark(const __FlashStringHelper *s, int line) { char __stack = 0; (void)(s); //Serial.print(s); Serial.print(F(" line:")); Serial.print(line); Serial.println(F(": Mark set")); mark_stack = ((unsigned int)&__stack - RAMSTART) + 1; mark_stack = stack_top - mark_stack; mark_heap = 0; if(__brkval != 0) { mark_heap = (unsigned int)__brkval - RAMSTART - heap_start; } } void showMark(const __FlashStringHelper *s, int line) { char __stack = 0; (void)(s); // Serial.print(s); Serial.print(F(" line:")); Serial.print(line); Serial.print(F(" : Mark")); stack_bottom = ((unsigned int)&__stack - RAMSTART) + 1; stack_size = stack_top - stack_bottom; if(__brkval != 0) { heap_end = (unsigned int)__brkval - RAMSTART; } else { heap_end = heap_start - RAMSTART; } heap_size = heap_end - heap_start; Serial.print(F(" stack: ")); Serial.print((int)stack_size - (int)mark_stack); Serial.print(F("/heap: ")); Serial.println((int)heap_size - (int)mark_heap); } void showSizes(const __FlashStringHelper *s, int line) { char __stack = 0; (void)(s); //Serial.print(s); Serial.print(F(" line:")); Serial.print(line); Serial.print(F(": ")); stack_bottom = (unsigned int)&__stack - RAMSTART + 1; stack_size = stack_top - stack_bottom; if(__brkval != 0) { heap_end = (unsigned int)__brkval - RAMSTART; } else { heap_end = heap_start - RAMSTART; } heap_size = heap_end - heap_start; free_size = stack_bottom - heap_end + freeListSize(); Serial.print(F(" free:")); Serial.print(free_size); Serial.print(F(" used:")); Serial.print(max_ram - free_size); Serial.print(F(" stack/heap: ")); Serial.print(stack_size); Serial.print(F("/")); Serial.print(heap_size); Serial.print(""); Serial.print("\n"); } int freeListSize() { total = 0; for (current = __flp; current; current = current->nx) { total += 2; /* Add two bytes for the memory block's header */ total += (int) current->sz; } return total; } int freeMemory() { int free_memory; if ((int)__brkval == 0) { free_memory = ((int)&free_memory) - ((int)&__heap_start); } else { free_memory = ((int)&free_memory) - ((int)__brkval); free_memory += freeListSize(); } return free_memory; } void showMem(void) { char __stack = 0; Serial.print(" __brkval="); Serial.print((unsigned int)__brkval); Serial.print(" __heap_start="); Serial.print((unsigned int)__heap_start); Serial.print(" __malloc_heap_start="); Serial.print((unsigned int)__malloc_heap_start); Serial.print(" __malloc_margin="); Serial.print((unsigned int)__malloc_margin); Serial.print(" __flp="); Serial.print((unsigned int)__flp); Serial.print(" __stack="); Serial.print((unsigned int)&__stack); Serial.print(" stack size="); Serial.print(RAMEND - (unsigned int)&__stack); Serial.print(" Heap size="); Serial.println((unsigned int)__brkval - RAMSTART); total = 0; for (current = __flp; current; current = current->nx) { total += 2; /* Add two bytes for the memory block's header */ total += (int) current->sz; Serial.print("mblk: sz="); Serial.print((unsigned int)current->sz); Serial.print(" nx="); Serial.println((unsigned int)current->nx); Serial.print("Total: "); Serial.println(total); } Serial.println("\n"); } void showMemory(const char *s) { // char __stack = 0; //(void)(s); Serial.println(s); showMem(); } void showMemory_P(const __FlashStringHelper *s) { //char __stack = 0; Serial.println(s); showMem(); } #ifdef ARDUINO_ARCH_AVR uint16_t getFreeHeap(); int getFreeListSize(); int getFreeListCount(); void getFreeList(); #endif void printHeapData() { // padd title to length 30 // while (title.length() < 30) { // title += ' '; // } // Serial.print(title); #ifdef ARDUINO_ARCH_AVR Serial.print(F(" freeHeap:")); Serial.print(getFreeHeap()); Serial.print(F(" freeListSize:")); Serial.print(getFreeListSize()); Serial.print(F(" freeListCount:")); Serial.print(getFreeListCount()); Serial.print(F(" Total Free Mem:")); Serial.print(getFreeListSize() + getFreeHeap()); getFreeList(); #else Serial.print(F(" -- this freeMemory code only supports AVR processors, e.g. UNO, MEGA2560")); #endif Serial.println(); } String string1; // 2 for heap427 buffer + buffersize in pairs ie even allocations StringReserveCheck string1Check; String string2; StringReserveCheck string2Check; String string3; StringReserveCheck string3Check; void setup() { Serial.begin(9600); for (int i = 10; i > 0; i--) { Serial.print(i); Serial.print(' '); delay(500); } Serial.println(); initFreeMemory(); Serial.println(F("initFreeMemory")); SHOW_SIZES // SET_MARK Serial.print(F("Before reserve")); printHeapData(); string1.reserve(800); string1Check.init(string1); // checkReserve( ) will not print any msgs, you need to check its return value string2.reserve(32); string2Check.init(string2, Serial); // init( ) will print a msg if memory is low and checkReserve( ) will print a msg if (!string3.reserve(490)) { Serial.println(F("string3.reserve(490) Failed")); } if (!string3Check.init(string3, Serial)) { // check return for low memory Serial.println(F("Memory Low after reserves()")); } SHOW_SIZES Serial.print(F("After reserve")); printHeapData(); Serial.println(F("Memory Fragementation Example 4 - Out Of Memory")); string1 = F("string1 initial value"); string3 = F("string3 initial value"); Serial.println(F("Memory Non-Fragementation Example 2")); } void printDegC(float value, String& result) { String title = "This is the temperature in the boiler room "; // String title = "Temperature "; String units = "degC"; Serial.print(F(" >> before formatResult")); printHeapData(); SHOW_SIZES SHOW_MARK formatResult(title, units, value, result); Serial.print(F(" >> after formatResult")); printHeapData(); SHOW_SIZES SHOW_MARK } void formatResult(String& title, String units, float value, String& result) { result = title; result += String(value,1); //temp to 1 decimal only result += units; Serial.print(F(">> end of formatResult")); printHeapData(); SHOW_SIZES SHOW_MARK } int count = 0; void loop() { SET_MARK count++; Serial.println(" ========================= "); Serial.print(F(" Loop : ")); Serial.println(count); //Serial.println(F("PrintVal, SHOW_SIZES,SHOW_MARK")); // SHOW_SIZES // SHOW_MARK //printHeapData(" !! start of loop"); //showMemory("start"); if (count > 2) { Serial.println("Stop here."); while (1) { } } float temp = 27.35; Serial.println(temp); Serial.print(F(" >> before printDegc")); printHeapData(); SHOW_SIZES SHOW_MARK //showMemory("after creating strings"); printDegC(temp, string2); Serial.println(string2); Serial.println(string2.length()); Serial.print(F(" >> after PrintVal returns")); string1Check.checkReserve(); // init(string1,Serial); was specified so msg printed if (!string2Check.checkReserve()) { // check return, init(string2,Serial); was specified so msg also printed Serial.print(F("string2 reserve to small. Current length():")); Serial.println(string2.length()); } if (!string3Check.checkReserve()) { // init(string3); // no output specified, check return Serial.print(F("string3 reserve to small. Current length():")); Serial.println(string3.length()); } Serial.println(); printHeapData(); SHOW_SIZES SHOW_MARK //showMemory("after PrintVal returns"); } #ifdef ARDUINO_ARCH_AVR extern unsigned int __heap_start; extern void *__brkval; extern uint16_t __heap_start; extern size_t __malloc_margin; /* The free list structure as maintained by the avr-libc memory allocation routines. */ //struct __freelist { // size_t sz; // struct __freelist *nx; //}; /* The head of the free list structure */ extern struct __freelist *__flp; uint16_t getFreeHeap() { // contiguous heap mem unused // int free_memory; uint16_t upperLimit = (uint16_t)((char*)AVR_STACK_POINTER_REG - __malloc_margin); uint16_t lowerLimit = ((uint16_t)__brkval == 0) ? (uint16_t)&__heap_start : (uint16_t)__brkval; uint16_t availableHeapSize = upperLimit - lowerLimit; return availableHeapSize; // if ((int)__brkval == 0) { // free_memory = ((int)&free_memory) - ((int)&__heap_start); // } else { // free_memory = ((int)&free_memory) - ((int)__brkval); // } // return free_memory; } void getFreeList() { Serial.println(F(" FreeList contents:")); struct __freelist* current; int total = 0; int count = 0; for (current = __flp; current; current = current->nx) { Serial.print(F(" free:"));Serial.print(count); total += 2; /* Add two bytes for the memory block's header */ total += (int) current->sz; Serial.print(F(" size:"));Serial.print(2+((int) current->sz)); Serial.println(); } } int getFreeListSize() { struct __freelist* current; int total = 0; for (current = __flp; current; current = current->nx) { total += 2; /* Add two bytes for the memory block's header */ total += (int) current->sz; } return total; } int getFreeListCount() { struct __freelist* current; int total = 0; for (current = __flp; current; current = current->nx) { total += 1; } return total; } #endif