Browse Source

Memory watcher

Richard Wackerbarth 9 years ago
parent
commit
ed7d45e8f5
3 changed files with 292 additions and 0 deletions
  1. 5
    0
      Marlin/Configuration.h
  2. 277
    0
      Marlin/M99_Free_Mem_Chk.cpp
  3. 10
    0
      Marlin/Marlin_main.cpp

+ 5
- 0
Marlin/Configuration.h View File

@@ -612,6 +612,11 @@ const bool Z_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the logic
612 612
   #define EEPROM_CHITCHAT // Please keep turned on if you can.
613 613
 #endif
614 614
 
615
+//
616
+// M99 Free Memory Watcher
617
+//
618
+#define M99_FREE_MEMORY_WATCHER // uncomment to add the M99 Free Memory Watcher for debug purpose
619
+
615 620
 // @section temperature
616 621
 
617 622
 // Preheat Constants

+ 277
- 0
Marlin/M99_Free_Mem_Chk.cpp View File

@@ -0,0 +1,277 @@
1
+#define M99_FREE_MEMORY_DUMPER			// Comment out to remove Dump sub-command
2
+#define M99_FREE_MEMORY_CORRUPTOR		// Comment out to remove Corrupt sub-command
3
+
4
+
5
+// M99 Free Memory Watcher
6
+//
7
+// This code watches the free memory block between the bottom of the heap and the top of the stack.
8
+// This memory block is initialized and watched via the M99 command.
9
+//
10
+// M99 I	Initializes the free memory block and prints vitals statistics about the area
11
+// M99 F	Identifies how much of the free memory block remains free and unused.  It also
12
+// 		detects and reports any corruption within the free memory block that may have
13
+// 		happened due to errant firmware.
14
+// M99 D	Does a hex display of the free memory block along with a flag for any errant
15
+// 		data that does not match the expected value.
16
+// M99 C x	Corrupts x locations within the free memory block.   This is useful to check the
17
+// 		correctness of the M99 F and M99 D commands.
18
+//
19
+// Initial version by Roxy-3DPrintBoard
20
+//
21
+//
22
+
23
+
24
+#include "Marlin.h"
25
+
26
+#ifdef M99_FREE_MEMORY_WATCHER
27
+extern void *__brkval;
28
+extern size_t  __heap_start, __heap_end, __flp;
29
+
30
+
31
+//
32
+// Declare all the functions we need from Marlin_Main.cpp to do the work!
33
+//
34
+
35
+float code_value();
36
+long code_value_long();
37
+bool code_seen(char );
38
+void serial_echopair_P(const char *, float );
39
+void serial_echopair_P(const char *, double );
40
+void serial_echopair_P(const char *, unsigned long );
41
+void serial_echopair_P(const char *, int );
42
+void serial_echopair_P(const char *, long );
43
+
44
+
45
+
46
+
47
+//
48
+// Utility functions used by M99 to get its work done.
49
+//
50
+
51
+unsigned char *top_of_stack();
52
+void prt_hex_nibble( unsigned int );
53
+void prt_hex_byte(unsigned int );
54
+void prt_hex_word(unsigned int );
55
+int how_many_E5s_are_here( unsigned char *);
56
+
57
+
58
+
59
+
60
+void m99_code()
61
+{
62
+static int m99_not_initialized=1;
63
+unsigned char *sp, *ptr;
64
+int i, j, n;
65
+
66
+//
67
+// M99 D dumps the free memory block from __brkval to the stack pointer.
68
+// malloc() eats memory from the start of the block and the stack grows
69
+// up from the bottom of the block.    Solid 0xE5's indicate nothing has
70
+// used that memory yet.   There should not be anything but 0xE5's within
71
+// the block of 0xE5's.  If there is, that would indicate memory corruption
72
+// probably caused by bad pointers.  Any unexpected values will be flagged in
73
+// the right hand column to help spotting them.
74
+//
75
+
76
+#ifdef M99_FREE_MEMORY_DUMPER			// Comment out to remove Dump sub-command
77
+	if ( code_seen('D') ) {
78
+ 		ptr = (unsigned char *) __brkval;
79
+
80
+//
81
+// We want to start and end the dump on a nice 16 byte boundry even though
82
+// the values we are using are not 16 byte aligned.
83
+//
84
+  		SERIAL_ECHOPGM("\n__brkval : ");
85
+		prt_hex_word( (unsigned int) ptr );
86
+  		ptr = (unsigned char *) ((unsigned long) ptr & 0xfff0);
87
+
88
+		sp = top_of_stack();
89
+  		SERIAL_ECHOPGM("\nStack Pointer : ");
90
+		prt_hex_word( (unsigned int) sp );
91
+  		SERIAL_ECHOPGM("\n");
92
+
93
+		sp = (unsigned char *) ((unsigned long) sp | 0x000f);
94
+		n = sp - ptr;
95
+//
96
+// This is the main loop of the Dump command.
97
+//
98
+		while ( ptr < sp ) {
99
+			prt_hex_word( (unsigned int) ptr);	// Print the address
100
+  			SERIAL_ECHOPGM(":");
101
+			for(i=0; i<16; i++) {			// and 16 data bytes
102
+				prt_hex_byte( *(ptr+i));
103
+  				SERIAL_ECHOPGM(" ");
104
+				delay(2);
105
+			}
106
+
107
+  			SERIAL_ECHO("|");   			// now show where non 0xE5's are
108
+			for(i=0; i<16; i++) {
109
+				delay(2);
110
+				if ( *(ptr+i)==0xe5)
111
+  					SERIAL_ECHOPGM(" ");
112
+				else
113
+  					SERIAL_ECHOPGM("?");
114
+			}
115
+  			SERIAL_ECHO("\n");
116
+
117
+			ptr += 16;
118
+			delay(2);
119
+		}
120
+  		SERIAL_ECHOLNPGM("Done.\n");
121
+		return;
122
+	}
123
+#endif
124
+
125
+//
126
+// M99 F   requests the code to return the number of free bytes in the memory pool along with
127
+// other vital statistics that define the memory pool.
128
+//
129
+	if ( code_seen('F') ) {
130
+	int max_addr = (int) __brkval;
131
+	int max_cnt = 0;
132
+	int block_cnt = 0;
133
+  		ptr = (unsigned char *) __brkval;
134
+		sp = top_of_stack();
135
+		n = sp - ptr;
136
+
137
+// Scan through the range looking for the biggest block of 0xE5's we can find
138
+
139
+		for(i=0; i<n; i++) {
140
+			if ( *(ptr+i) == (unsigned char) 0xe5) {
141
+				j = how_many_E5s_are_here( (unsigned char *) ptr+i );
142
+				if ( j>8) {
143
+ 					SERIAL_ECHOPAIR("Found ", j );
144
+ 					SERIAL_ECHOPGM(" bytes free at 0x");
145
+					prt_hex_word( (int) ptr+i );
146
+ 					SERIAL_ECHOPGM("\n");
147
+					i += j;
148
+				        block_cnt++;
149
+				}
150
+				if ( j>max_cnt) {			// We don't do anything with this information yet
151
+					max_cnt  = j;			// but we do know where the biggest free memory block is.
152
+					max_addr = (int) ptr+i;
153
+				}
154
+			}
155
+		}
156
+		if (block_cnt>1)
157
+  			SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.\n");
158
+
159
+  		SERIAL_ECHO("\nDone.\n");
160
+		return;
161
+	}
162
+//
163
+// M99 C x  Corrupts x locations in the free memory pool and reports the locations of the corruption.
164
+// This is useful to check the correctness of the M99 D and the M99 F commands.
165
+//
166
+#ifdef M99_FREE_MEMORY_CORRUPTOR
167
+	if ( code_seen('C') ) {
168
+		int x;			// x gets the # of locations to corrupt within the memory pool
169
+		x = code_value();
170
+  		SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
171
+  		ptr = (unsigned char *) __brkval;
172
+  		SERIAL_ECHOPAIR("\n__brkval : ",(long) ptr );
173
+  		ptr += 8;
174
+
175
+		sp = top_of_stack();
176
+  		SERIAL_ECHOPAIR("\nStack Pointer : ",(long) sp );
177
+  		SERIAL_ECHOLNPGM("\n");
178
+
179
+		n = sp - ptr - 64;  	// -64 just to keep us from finding interrupt activity that
180
+	       				// has altered the stack.
181
+		j = n / (x+1);
182
+		for(i=1; i<=x; i++) {
183
+			*(ptr+(i*j)) = i;
184
+  			SERIAL_ECHO("\nCorrupting address: 0x");
185
+		      	prt_hex_word( (unsigned int)  (ptr+(i*j)) );
186
+		}
187
+  		SERIAL_ECHOLNPGM("\n");
188
+		return;
189
+	}
190
+#endif
191
+
192
+//
193
+// M99 I    Initializes the free memory pool so it can be watched and prints vital
194
+// statistics that define the free memory pool.
195
+//
196
+	if (m99_not_initialized || code_seen('I') ) {				// If no sub-command is specified, the first time
197
+  		SERIAL_ECHOLNPGM("Initializing free memory block.\n");   	// this happens, it will Initialize.
198
+  		ptr = (unsigned char *) __brkval;				// Repeated M99 with no sub-command will not destroy the
199
+  		SERIAL_ECHOPAIR("\n__brkval : ",(long) ptr );			// state of the initialized free memory pool.
200
+  		ptr += 8;
201
+
202
+		sp = top_of_stack();
203
+  		SERIAL_ECHOPAIR("\nStack Pointer : ",(long) sp );
204
+  		SERIAL_ECHOLNPGM("\n");
205
+
206
+		n = sp - ptr - 64;  	// -64 just to keep us from finding interrupt activity that
207
+	       				// has altered the stack.
208
+
209
+  		SERIAL_ECHO( n );
210
+  		SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
211
+
212
+		for(i=0; i<n; i++)
213
+			*(ptr+i) = (unsigned char) 0xe5;
214
+
215
+		for(i=0; i<n; i++) {
216
+			if ( *(ptr+i) != (unsigned char) 0xe5 ) {
217
+  				SERIAL_ECHOPAIR("? address : ", (unsigned long) ptr+i );
218
+  				SERIAL_ECHOPAIR("=", *(ptr+i) );
219
+  				SERIAL_ECHOLNPGM("\n");
220
+			}
221
+		}
222
+		m99_not_initialized = 0;
223
+  		SERIAL_ECHOLNPGM("Done.\n");
224
+		return;
225
+	}
226
+	return;
227
+}
228
+
229
+// top_of_stack() returns the location of a variable on its stack frame.  The value returned is above
230
+// the stack once the function returns to the caller.
231
+
232
+unsigned char *top_of_stack() {
233
+unsigned char x;
234
+	return &x;
235
+}
236
+
237
+//
238
+// 3 support routines to print hex numbers.  We can print a nibble, byte and word
239
+//
240
+
241
+void prt_hex_nibble( unsigned int n )
242
+{
243
+	if ( n <= 9 )
244
+		SERIAL_ECHO(n);
245
+	else
246
+		SERIAL_ECHO( (char) ('A'+n-10) );
247
+	delay(2);
248
+}
249
+
250
+void prt_hex_byte(unsigned int b)
251
+{
252
+	prt_hex_nibble( ( b & 0xf0 ) >> 4 );
253
+	prt_hex_nibble(  b & 0x0f );
254
+}
255
+
256
+void prt_hex_word(unsigned int w)
257
+{
258
+	prt_hex_byte( ( w & 0xff00 ) >> 8 );
259
+	prt_hex_byte(  w & 0x0ff );
260
+}
261
+
262
+// how_many_E5s_are_here() is a utility function to easily find out how many 0xE5's are
263
+// at the specified location.  Having this logic as a function simplifies the search code.
264
+//
265
+int how_many_E5s_are_here( unsigned char *p)
266
+{
267
+int n;
268
+
269
+	for(n=0; n<32000; n++) {
270
+		if ( *(p+n) != (unsigned char) 0xe5)
271
+			return n-1;
272
+	}
273
+	return -1;
274
+}
275
+
276
+#endif
277
+

+ 10
- 0
Marlin/Marlin_main.cpp View File

@@ -225,6 +225,10 @@
225 225
  *
226 226
  */
227 227
 
228
+#ifdef M99_FREE_MEMORY_WATCHER
229
+  void m99_code();
230
+#endif
231
+
228 232
 #ifdef SDSUPPORT
229 233
   CardReader card;
230 234
 #endif
@@ -5372,6 +5376,12 @@ void process_next_command() {
5372 5376
           break;
5373 5377
       #endif // ENABLE_AUTO_BED_LEVELING && Z_PROBE_REPEATABILITY_TEST
5374 5378
 
5379
+      #ifdef M99_FREE_MEMORY_WATCHER
5380
+        case 99:
5381
+          m99_code();
5382
+          break;
5383
+      #endif
5384
+
5375 5385
       case 104: // M104
5376 5386
         gcode_M104();
5377 5387
         break;

Loading…
Cancel
Save