Quellcode durchsuchen

M100 Fixes and Features

All the memory accesses need to be unsigned char in  order to avoid
false errors being detected.   Two new features are available for
developers to call into the M100 functionality to look for data
corruption.
Roxy-3D vor 7 Jahren
Ursprung
Commit
28fec61f92
1 geänderte Dateien mit 101 neuen und 36 gelöschten Zeilen
  1. 101
    36
      Marlin/M100_Free_Mem_Chk.cpp

+ 101
- 36
Marlin/M100_Free_Mem_Chk.cpp Datei anzeigen

@@ -38,6 +38,11 @@
38 38
  * M100 C x Corrupts x locations within the free memory block. This is useful to check the
39 39
  *          correctness of the M100 F and M100 D commands.
40 40
  *
41
+ * Also, there are two support functions that can be called from a developer's C code.
42
+ *
43
+ *    uint16_t check_for_free_memory_corruption(char * const ptr);
44
+ *    void M100_dump_free_memory(char *ptr, char *sp);
45
+ *
41 46
  * Initial version by Roxy-3D
42 47
  */
43 48
 #define M100_FREE_MEMORY_DUMPER     // Enable for the `M110 D` Dump sub-command
@@ -47,7 +52,7 @@
47 52
 
48 53
 #if ENABLED(M100_FREE_MEMORY_WATCHER)
49 54
 
50
-#define TEST_BYTE 0xE5
55
+#define TEST_BYTE ((uint8_t) 0xE5)
51 56
 
52 57
 extern char* __brkval;
53 58
 extern size_t  __heap_start, __heap_end, __flp;
@@ -61,6 +66,7 @@ extern char __bss_end;
61 66
 //
62 67
 
63 68
 #define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
69
+int check_for_free_memory_corruption(char *title);
64 70
 
65 71
 // Location of a variable on its stack frame. Returns a value above
66 72
 // the stack (once the function returns to the caller).
@@ -70,7 +76,7 @@ char* top_of_stack() {
70 76
 }
71 77
 
72 78
 // Count the number of test bytes at the specified location.
73
-int16_t count_test_bytes(const char * const ptr) {
79
+int16_t count_test_bytes(const uint8_t * const ptr) {
74 80
   for (uint16_t i = 0; i < 32000; i++)
75 81
     if (ptr[i] != TEST_BYTE)
76 82
       return i - 1;
@@ -78,27 +84,6 @@ int16_t count_test_bytes(const char * const ptr) {
78 84
   return -1;
79 85
 }
80 86
 
81
-// Return a count of free memory blocks.
82
-uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
83
-  // Find the longest block of test bytes in the given buffer
84
-  uint16_t block_cnt = 0;
85
-  for (uint16_t i = 0; i < size; i++) {
86
-    if (ptr[i] == TEST_BYTE) {
87
-      const uint16_t j = count_test_bytes(ptr + i);
88
-      if (j > 8) {
89
-        //SERIAL_ECHOPAIR("Found ", j);
90
-        //SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)ptr + i));
91
-        i += j;
92
-        block_cnt++;
93
-      }
94
-    }
95
-  }
96
-  //if (block_cnt > 1) {
97
-  //  SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
98
-  //  SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
99
-  //}
100
-  return block_cnt;
101
-}
102 87
 
103 88
 //
104 89
 // M100 sub-commands
@@ -114,13 +99,13 @@ uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
114 99
    *  the block. If so, it may indicate memory corruption due to a bad pointer.
115 100
    *  Unexpected bytes are flagged in the right column.
116 101
    */
117
-  void dump_free_memory(char *ptr, char *sp) {
102
+  void dump_free_memory(uint8_t *ptr, uint8_t *sp) {
118 103
     //
119 104
     // Start and end the dump on a nice 16 byte boundary
120 105
     // (even though the values are not 16-byte aligned).
121 106
     //
122
-    ptr = (char*)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary
123
-    sp  = (char*)((uint16_t)sp  | 0x000F); // Align sp to the 15th byte (at or above sp)
107
+    ptr = (uint8_t *)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary
108
+    sp  = (uint8_t *)((uint16_t)sp  | 0x000F); // Align sp to the 15th byte (at or above sp)
124 109
 
125 110
     // Dump command main loop
126 111
     while (ptr < sp) {
@@ -131,14 +116,30 @@ uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
131 116
         print_hex_byte(ptr[i]);
132 117
         SERIAL_CHAR(' ');
133 118
       }
119
+      safe_delay(25);
134 120
       SERIAL_CHAR('|');                   // Point out non test bytes
135 121
       for (uint8_t i = 0; i < 16; i++)
136 122
         SERIAL_CHAR(ptr[i] == TEST_BYTE ? ' ' : '?');
137 123
       SERIAL_EOL;
138 124
       ptr += 16;
125
+      safe_delay(25);
139 126
       idle();
140 127
     }
141 128
   }
129
+
130
+void M100_dump_routine( char *title, char *start, char *end) {
131
+unsigned char c;
132
+int i;
133
+
134
+//
135
+// Round the start and end locations to produce full lines of output
136
+//
137
+      start = (char*) ((uint16_t) start & 0xfff0);
138
+      end   = (char*) ((uint16_t) end   | 0x000f);
139
+
140
+      SERIAL_ECHOLN(title);
141
+      dump_free_memory( start, end );
142
+}
142 143
 #endif // M100_FREE_MEMORY_DUMPER
143 144
 
144 145
 /**
@@ -172,7 +173,7 @@ void free_memory_pool_report(const char * const ptr, const uint16_t size) {
172 173
     SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
173 174
     SERIAL_ECHOLNPAIR(" bytes at 0x", hex_word((uint16_t)max_addr));
174 175
   }
175
-  SERIAL_ECHOLNPAIR("free_memory_is_corrupted() = ", free_memory_is_corrupted(ptr, size));
176
+  SERIAL_ECHOLNPAIR("check_for_free_memory_corruption() = ", check_for_free_memory_corruption("M100 F "));
176 177
 }
177 178
 
178 179
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
@@ -202,13 +203,17 @@ void free_memory_pool_report(const char * const ptr, const uint16_t size) {
202 203
  * M100 I
203 204
  *  Init memory for the M100 tests. (Automatically applied on the first M100.)
204 205
  */
205
-void init_free_memory(char *ptr, int16_t size) {
206
+void init_free_memory(uint8_t *ptr, int16_t size) {
206 207
   SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
207 208
 
208 209
   size -= 250;    // -250 to avoid interrupt activity that's altered the stack.
209
-  if (size < 0) return;
210
+  if (size < 0) {
211
+    SERIAL_ECHOLNPGM("Unable to initialize.\n");
212
+    return;
213
+  }
210 214
 
211
-  ptr += 8;
215
+  ptr += 8;       // move a few bytes away from the heap just because we don't want
216
+                  // to be altering memory that close to it.
212 217
   memset(ptr, TEST_BYTE, size);
213 218
 
214 219
   SERIAL_ECHO(size);
@@ -217,8 +222,7 @@ void init_free_memory(char *ptr, int16_t size) {
217 222
   for (uint16_t i = 0; i < size; i++) {
218 223
     if (ptr[i] != TEST_BYTE) {
219 224
       SERIAL_ECHOPAIR("? address : 0x", hex_word((uint16_t)ptr + i));
220
-      SERIAL_ECHOPAIR("=", hex_byte(ptr[i]));
221
-      SERIAL_EOL; SERIAL_EOL;
225
+      SERIAL_ECHOLNPAIR("=", hex_byte(ptr[i]));
222 226
     }
223 227
   }
224 228
 }
@@ -228,9 +232,9 @@ void init_free_memory(char *ptr, int16_t size) {
228 232
  */
229 233
 void gcode_M100() {
230 234
   SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval));
231
-  SERIAL_ECHOPAIR("\n__bss_end : 0x", hex_word((uint16_t)&__bss_end));
235
+  SERIAL_ECHOPAIR("\n__bss_end: 0x", hex_word((uint16_t)&__bss_end));
232 236
 
233
-  char *ptr = END_OF_HEAP(), *sp = top_of_stack();
237
+  uint8_t *ptr = END_OF_HEAP(), *sp = top_of_stack();
234 238
 
235 239
   SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
236 240
   SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
@@ -243,10 +247,8 @@ void gcode_M100() {
243 247
   }
244 248
 
245 249
   #if ENABLED(M100_FREE_MEMORY_DUMPER)
246
-
247 250
     if (code_seen('D'))
248 251
       return dump_free_memory(ptr, sp);
249
-
250 252
   #endif
251 253
 
252 254
   if (code_seen('F'))
@@ -260,4 +262,67 @@ void gcode_M100() {
260 262
   #endif
261 263
 }
262 264
 
265
+int check_for_free_memory_corruption(char *title) {
266
+  char *sp, *ptr;
267
+  int block_cnt = 0, i, j, n;
268
+
269
+    SERIAL_ECHO(title);
270
+
271
+    ptr = __brkval ? __brkval : &__bss_end;    
272
+    sp = top_of_stack();
273
+
274
+    n = sp - ptr;
275
+    SERIAL_ECHOPAIR("\nfmc() n=", n);
276
+    SERIAL_ECHOPAIR("\n&__brkval: 0x", hex_word((uint16_t)&__brkval));
277
+    SERIAL_ECHOPAIR("=0x",             hex_word((uint16_t)__brkval));
278
+    SERIAL_ECHOPAIR("\n__bss_end: 0x", hex_word((uint16_t)&__bss_end));
279
+    SERIAL_ECHOPAIR(" sp=", hex_word(sp));
280
+
281
+    if (sp < ptr)  {
282
+        SERIAL_ECHOPGM(" sp < Heap ");
283
+//      SET_INPUT_PULLUP(63);		// if the developer has a switch wired up to their controller board
284
+//      safe_delay(5);                  // this code can be enabled to pause the display as soon as the 
285
+//      while ( READ(63))               // malfunction is detected.   It is currently defaulting to a switch
286
+//        idle();                       // being on pin-63 which is unassigend and available on most controller 
287
+//      safe_delay(20);                 // boards.
288
+//      while ( !READ(63))
289
+//        idle();
290
+        safe_delay(20);
291
+        M100_dump_routine( "   Memory corruption detected with sp<Heap\n", (char *)0x1b80,  0x21ff );
292
+    }
293
+
294
+    // Scan through the range looking for the biggest block of 0xE5's we can find
295
+    for (i = 0; i < n; i++) {
296
+      if (*(ptr + i) == (char)0xe5) {
297
+        j = count_test_bytes(ptr + i);
298
+        if (j > 8) {
299
+//        SERIAL_ECHOPAIR("Found ", j);
300
+//        SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
301
+
302
+          i += j;
303
+          block_cnt++;
304
+          SERIAL_ECHOPAIR(" (", block_cnt);
305
+          SERIAL_ECHOPAIR(") found=", j);
306
+          SERIAL_ECHOPGM("   ");
307
+        }
308
+      }
309
+    }
310
+    SERIAL_ECHOPAIR("  block_found=", block_cnt);
311
+
312
+    if ((block_cnt!=1) || (__brkval != 0x0000)) 
313
+      SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
314
+
315
+    if ((block_cnt==0))		       // Make sure the special case of no free blocks shows up as an
316
+      block_cnt = -1;                  // error to the calling code!
317
+
318
+    if (block_cnt==1) {              
319
+      SERIAL_ECHOPGM(" return=0\n");  // if the block_cnt is 1, nothing has broken up the free memory
320
+      return 0;                       // area and it is appropriate to say 'no corruption'.
321
+    }
322
+    SERIAL_ECHOPGM(" return=true\n");
323
+    return block_cnt;
324
+  }
325
+
263 326
 #endif // M100_FREE_MEMORY_WATCHER
327
+
328
+

Laden…
Abbrechen
Speichern