Browse Source

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 7 years ago
parent
commit
28fec61f92
1 changed files with 101 additions and 36 deletions
  1. 101
    36
      Marlin/M100_Free_Mem_Chk.cpp

+ 101
- 36
Marlin/M100_Free_Mem_Chk.cpp View File

38
  * M100 C x Corrupts x locations within the free memory block. This is useful to check the
38
  * M100 C x Corrupts x locations within the free memory block. This is useful to check the
39
  *          correctness of the M100 F and M100 D commands.
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
  * Initial version by Roxy-3D
46
  * Initial version by Roxy-3D
42
  */
47
  */
43
 #define M100_FREE_MEMORY_DUMPER     // Enable for the `M110 D` Dump sub-command
48
 #define M100_FREE_MEMORY_DUMPER     // Enable for the `M110 D` Dump sub-command
47
 
52
 
48
 #if ENABLED(M100_FREE_MEMORY_WATCHER)
53
 #if ENABLED(M100_FREE_MEMORY_WATCHER)
49
 
54
 
50
-#define TEST_BYTE 0xE5
55
+#define TEST_BYTE ((uint8_t) 0xE5)
51
 
56
 
52
 extern char* __brkval;
57
 extern char* __brkval;
53
 extern size_t  __heap_start, __heap_end, __flp;
58
 extern size_t  __heap_start, __heap_end, __flp;
61
 //
66
 //
62
 
67
 
63
 #define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
68
 #define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
69
+int check_for_free_memory_corruption(char *title);
64
 
70
 
65
 // Location of a variable on its stack frame. Returns a value above
71
 // Location of a variable on its stack frame. Returns a value above
66
 // the stack (once the function returns to the caller).
72
 // the stack (once the function returns to the caller).
70
 }
76
 }
71
 
77
 
72
 // Count the number of test bytes at the specified location.
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
   for (uint16_t i = 0; i < 32000; i++)
80
   for (uint16_t i = 0; i < 32000; i++)
75
     if (ptr[i] != TEST_BYTE)
81
     if (ptr[i] != TEST_BYTE)
76
       return i - 1;
82
       return i - 1;
78
   return -1;
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
 // M100 sub-commands
89
 // M100 sub-commands
114
    *  the block. If so, it may indicate memory corruption due to a bad pointer.
99
    *  the block. If so, it may indicate memory corruption due to a bad pointer.
115
    *  Unexpected bytes are flagged in the right column.
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
     // Start and end the dump on a nice 16 byte boundary
104
     // Start and end the dump on a nice 16 byte boundary
120
     // (even though the values are not 16-byte aligned).
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
     // Dump command main loop
110
     // Dump command main loop
126
     while (ptr < sp) {
111
     while (ptr < sp) {
131
         print_hex_byte(ptr[i]);
116
         print_hex_byte(ptr[i]);
132
         SERIAL_CHAR(' ');
117
         SERIAL_CHAR(' ');
133
       }
118
       }
119
+      safe_delay(25);
134
       SERIAL_CHAR('|');                   // Point out non test bytes
120
       SERIAL_CHAR('|');                   // Point out non test bytes
135
       for (uint8_t i = 0; i < 16; i++)
121
       for (uint8_t i = 0; i < 16; i++)
136
         SERIAL_CHAR(ptr[i] == TEST_BYTE ? ' ' : '?');
122
         SERIAL_CHAR(ptr[i] == TEST_BYTE ? ' ' : '?');
137
       SERIAL_EOL;
123
       SERIAL_EOL;
138
       ptr += 16;
124
       ptr += 16;
125
+      safe_delay(25);
139
       idle();
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
 #endif // M100_FREE_MEMORY_DUMPER
143
 #endif // M100_FREE_MEMORY_DUMPER
143
 
144
 
144
 /**
145
 /**
172
     SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
173
     SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
173
     SERIAL_ECHOLNPAIR(" bytes at 0x", hex_word((uint16_t)max_addr));
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
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
179
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
202
  * M100 I
203
  * M100 I
203
  *  Init memory for the M100 tests. (Automatically applied on the first M100.)
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
   SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
207
   SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
207
 
208
 
208
   size -= 250;    // -250 to avoid interrupt activity that's altered the stack.
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
   memset(ptr, TEST_BYTE, size);
217
   memset(ptr, TEST_BYTE, size);
213
 
218
 
214
   SERIAL_ECHO(size);
219
   SERIAL_ECHO(size);
217
   for (uint16_t i = 0; i < size; i++) {
222
   for (uint16_t i = 0; i < size; i++) {
218
     if (ptr[i] != TEST_BYTE) {
223
     if (ptr[i] != TEST_BYTE) {
219
       SERIAL_ECHOPAIR("? address : 0x", hex_word((uint16_t)ptr + i));
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
  */
232
  */
229
 void gcode_M100() {
233
 void gcode_M100() {
230
   SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval));
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
   SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
239
   SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
236
   SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
240
   SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
243
   }
247
   }
244
 
248
 
245
   #if ENABLED(M100_FREE_MEMORY_DUMPER)
249
   #if ENABLED(M100_FREE_MEMORY_DUMPER)
246
-
247
     if (code_seen('D'))
250
     if (code_seen('D'))
248
       return dump_free_memory(ptr, sp);
251
       return dump_free_memory(ptr, sp);
249
-
250
   #endif
252
   #endif
251
 
253
 
252
   if (code_seen('F'))
254
   if (code_seen('F'))
260
   #endif
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
 #endif // M100_FREE_MEMORY_WATCHER
326
 #endif // M100_FREE_MEMORY_WATCHER
327
+
328
+

Loading…
Cancel
Save